像素读取和操作
1. 利用cv::Mat的at函数,直接访问具体地址
void get_setImagePixel(char *imagePath, int x, int y){// Mat image = imread(imagePath , 0);Mat image = imread(imagePath, 1);//得宽高int w = image.cols;int h = image.rows;int channels = image.channels();if (x < w && y < h){//灰度图,像素为单通道if (channels == 1){int pixel = image.at<uchar>(x, y);cout << "灰度图像,处的灰度值为" << pixel << endl;}else{//通过实验,彩色图像的默认存储是bgr, 且存储的格式如下//读取int b = image.at<Vec3b>(x, y)[0]; // b = image.at<uchar>(x,y*3);cout << b << endl;int g = image.at<Vec3b>(x, y)[1]; //g = image.at<uchar>(x, y * 3 + 1);cout << g << endl;int r = image.at<Vec3b>(x, y)[2]; //r = image.at<uchar>(x, y * 3 + 1);cout << r << endl;//设置像素值image.at<Vec3b>(x, y)[0] = 255;image.at<Vec3b>(x, y)[1] = 255;image.at<Vec3b>(x, y)[2] = 255;}}imshow("cc", image);}
2. 利用Mat 的prt 函数:行首地址访问
void get_setImagePixel2(char *imagePath, int x, int y){Mat image = imread(imagePath, 1);//得宽高int w = image.cols;int h = image.rows;int channels = image.channels();//如果图像连续 ,可以将数据转化为1维数组,提高访问效率,但对少量像素访问就没必要//if (image.isContinuous())//{// //reshape函数用于改变矩阵维度 // //图像行数为1,列数为原先的行数乘上列数 // image.reshape(1, image.cols*image.rows);//}//获得第y行的首地址uchar *data = image.ptr<uchar>(y);int position = x*channels;if (channels == 1){int pixel = data[position];cout << "灰度图像,处的灰度值为" << pixel << endl;}else{//通过实验,彩色图像的默认存储是bgr, 且存储的格式如下//读取int b = data[position];cout << b << endl;int g = data[position+1];cout << g << endl;int r = data[position+2];cout << r << endl;//设置像素值data[position] = 255;data[position+1] = 255;data[position+2] = 255;}imshow("cc", image);}
3. 利用迭代器遍历图像
void get_setImagePixel3(char *imagePath, int x, int y){Mat image = imread(imagePath, 1);//得宽高int w = image.cols;int h = image.rows;int channels = image.channels();if (channels == 1){//得到初始位置的迭代器 Mat_<uchar>::iterator it = image.begin<uchar>();//得到终止位置的迭代器 Mat_<uchar>::iterator itend = image.end<uchar>();int pixel = *(it + y * w + x);cout << "灰度图像,处的灰度值为" << pixel << endl;}else{//得到初始位置的迭代器 Mat_<Vec3b>::iterator it = image.begin<Vec3b>();//得到终止位置的迭代器 Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//读取it = it + y * w + x;int b = (*it)[0];cout << b << endl;int g = (*it)[1];cout << g << endl;int r = (*it)[2];cout << r << endl;//设置像素值(*it)[0] = 255;(*it)[1] = 255;(*it)[2] = 255;}imshow("cc", image);}
若是大量访问数据和更改数据时用第二种方式效率高。
Node: 在修改像素时候,最好先用变量存储,设定好了再赋值给Mat成员对象,如data,因为如果直接进行操作时,当一个分量值大于255时,向前进1的原则,则会修改前面像素的值,如下:
id colorReduce(cv::Mat&image, int div){int nl = image.rows; //图像的行数 //图像每行的像素数 int nc = image.cols * image.channels();for (int j = 0; j<nl; j++){//得到第j行的首地址 uchar* data = image.ptr<uchar>(j);//遍历每行的像素 for (int i = 0; i<nc; i++){//printf("%d ", data[i]);//data[i] = data[i] / div*div + 6;// 这里需要用c来存储,因为如果大于255时会向前进1,则影响前面的像素,data[i] 会自己变得小255int c = data[i] / div*div + 100; data[i] = c > 255 ? 255 : c; //将每个像素值都变为div的倍数,即将颜色数缩减了div倍 }}