常用类型介绍
- uchar类型
typedef unsigned uint;
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
Vec系列
Vec+数字+字母: C++STL vector容器类似
- 数字: Vec 的长度
- 字母: 类型
- b: uchar
- s:short
- w: ushort
- i: int
- f:float
- d:double
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
图像的像素读写
数组方式读写
int dims = img.channels(); //得到图片通道数
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
//单通道图像像素点获取
int pixel = img.at<uchar>(i, j);
img.at<uchar>(i, j) = 255 - pixel; //负片处理
}
if (dims == 3)
{
//三通道图像像素点获取
Vec3b bgr = img.at<Vec3b>(i, j);
//负片处理
img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
}
}
}
指针方式读写
//二维数组-->一级指针访问二维数组方式
int dims = img.channels();
for (int i = 0; i < img.rows; i++)
{
//Mat中有一个ptr成员函数,获取当前i行的指针
uchar* current_row = img.ptr<uchar>(i);
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
int pixel = *current_row; //current_row[j];
*current_row++ = 255 - pixel; //做一个横向移动
}
if (dims == 3)
{
Vec3b bgr = img.at<Vec3b>(i, j);
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
完整案例
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class ImgVisitPixel
{
public:
ImgVisitPixel(int type = IMREAD_UNCHANGED) :img(imread("mm.jpg",type)) {}
void Show(string wName)
{
imshow(wName, img);
moveWindow(wName, 600, 300);
waitKey(0);
}
void Visit_By_Array();
void Visit_By_Point();
protected:
Mat img;
};
void ImgVisitPixel::Visit_By_Array()
{
int dims = img.channels(); //得到图片通道数
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
//单通道图像像素点获取
int pixel = img.at<uchar>(i, j);
img.at<uchar>(i, j) = 255 - pixel; //负片处理
}
if (dims == 3)
{
//三通道图像像素点获取
Vec3b bgr = img.at<Vec3b>(i, j);
//负片处理
img.at<Vec3b>(i, j)[0] = 255 - bgr[0];
img.at<Vec3b>(i, j)[1] = 255 - bgr[1];
img.at<Vec3b>(i, j)[2] = 255 - bgr[2];
}
}
}
}
void ImgVisitPixel::Visit_By_Point()
{
int dims = img.channels();
for (int i = 0; i < img.rows; i++)
{
//Mat中有一个ptr成员函数,获取当前i行的指针
uchar* current_row = img.ptr<uchar>(i);
for (int j = 0; j < img.cols; j++)
{
if (dims == 1)
{
int pixel = *current_row; //current_row[j];
*current_row++ = 255 - pixel; //做一个横向移动
}
if (dims == 3)
{
Vec3b bgr = img.at<Vec3b>(i, j);
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
}
int main()
{
ImgVisitPixel* pImg = new ImgVisitPixel;
pImg->Show("原图");
pImg->Visit_By_Array();
pImg->Show("第一次负片操作");
pImg->Visit_By_Point();
pImg->Show("第二次负片操作");
return 0;
}
像素读写注意点
在读取到像素点的时候,做一些算数运算,一定要注意颜色范围问题,小心溢出,针对溢出,opencv提供一个转换防止溢出
saturate_cast<要转换的类型>(要转换的数据)
- 小于0 等于0
- 大于255 直接等于255
img.at<Vec3b>(i, j)[0] =saturate_cast<uchar>(bgr[0]+100);
img.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(bgr[1] + 100);
img.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(bgr[2] + 100);