#include
#include
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
Mat src = imread("E:/Desktop/y.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
// 直接读取图像像素
int height = src.rows;
int width = src.cols;
int ch = src.channels();
//for (int c = 0; c < ch; c++) {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (ch == 3) {
Vec3b bgr = src.at<Vec3b>(row, col);
bgr[0] = 255 - bgr[0];
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];
src.at<Vec3b>(row, col) = bgr;
}
else if (ch == 1) {
int gray = src.at<uchar>(row, col);
src.at<uchar>(row, col) = 255 - gray;
}
}
}
//}
imshow("output", src);
// 指针读取
Mat result = Mat::zeros(src.size(), src.type());
int blue = 0, green = 0, red = 0;
int gray;
//for (int c = 0; c < ch; c++) {
for (int row = 0; row < height; row++) {
uchar* curr_row = src.ptr<uchar>(row);
uchar* result_row = result.ptr<uchar>(row);
for (int col = 0; col < width; col++) {
if (ch == 3) {
blue = *curr_row++;
green = *curr_row++;
red = *curr_row++;
*result_row++ = blue;
*result_row++ = green;
*result_row++ = red;
/*
*result_row++ = 255 - blue;
*result_row++ = 255 - green;
*result_row++ = 255 - red;
*/
}
else if (ch == 1) {
gray = *curr_row++;
*result_row++ = gray;
}
}
}
//}
imshow("result", result);
waitKey(0);
return 0;
}
输出:
以上使用了两种方式对图像进行颜色反转,一种是数组遍历的方式,另一种是指针方式的遍历。
代码中获取了图像的通道:
int ch = src.channels();
学过图像处理的小伙伴们应该知道,我们彩色图片是由BGR三种通道的图片混合叠加而成的,彩色图片通道数就是3,也就是ch=3,当ch=1时是黑白图像。
后期我们也会接触到额外增加的一个透明通道,后期再讲。
对于三通道来说,每一个像素的位置内含了三个uchar
数据,所以对三通道获取像素值要使用Vec3b
。Vec3b
实质上是一个uchar
的数组,最多能装三个数据。
对于单通道,可以直接使用mat.at
即可获取像素值。
三通道图像读取像素值的代码如下:
int main(){
Mat src = Mat::zeros(5, 5, CV_8UC3);//建立一个三通道的图像
cout << "src"<<endl<<src << endl;
Vec3b i = src.at<Vec3b>(2, 2);//获取(2,2)位置的像素值,这里用了mat.at(2,2),返回一个Vec3b类型的数组
cout << "i" << endl << i << endl;
int a = (int)i[0];//因为Vec3b是uchar型,i[0]中是\0,就是空格。这里要转换为int
cout << a << endl;
waitKey(0);
return 0;
}
单通道的图像读取像素值的代码如下:
int main()
{
Mat src = Mat::zeros(5, 5, CV_8UC1);//建立一个三通道的图像
cout << "src"<<endl<<src << endl;
uchar i = src.at<uchar>(2, 2);//获取(2,2)位置的像素值,这里用了mat.at(2,2),返回一个Vec3b类型的数组
cout << "i" << endl << (int)i << endl;//i是uchar型,是\0,即空格,无法在doc中显示,所以使用int强制转换。
waitKey(0);
return 0;
}
最后,这种方法访问速度很慢,使用mat.ptr(i,j)(单通道) mat,ptr(i,j) (3通道)会快很多
更多at方法参考:
opencv图像操作——at方法使用
使用mat.at方法获取像素值
在对彩色图片进行处理的时候我们注意到这行代码:
Vec3b bgr = src.at<Vec3b>(row, col);
Vec3b
可以看作是vector
。
简单而言就是一个uchar
类型的,长度为3的vector
向量。
由于在OpenCV中,使用imread读取到的Mat图像数据,都是用uchar类型的数据存储,对于RGB三通道的图像,每个点的数据都是一个Vec3b类型的数据。使用at定位方法如下:
故:
bgr[0] = 255 - bgr[0];
bgr[1] = 255 - bgr[1];
bgr[2] = 255 - bgr[2];
这三行代码是对每个通道的像素数据取反(颜色取反是用255减去,因为像素值的取值范围是0~255)
在指针读取的那段代码中有一句:
uchar* curr_row = src.ptr<uchar>(row);
这个API接口的意义是读取src按row读取的像素坐标的首地址赋给curr_row
。