目录
读写图像
之前已经介绍过的两个函数:
imread 可以指定加载为灰度或者RGB图像
imwrite保存图像文件,类型由扩展名决定
具体介绍可以参考我的另一篇文章:
https://blog.csdn.net/milkhoko/article/details/111997017
读写像素
灰度图像像素点值的获取
Scalar intensity_gray = gray_src.at<uchar>(120,200);
或者
Scalar intensity_gray = gray_src.at<uchar>(Point(200,120));
注意这里小括号中x,y的顺序,当使用Point()时是先x后y,不使用时是先y后x,即先行数再列数。
说明:
图像左上角为坐标原点,向右为x轴正向,向下为y轴正向
Scalar intensity = img.at(y, x);
或
Scalar intensity = img.at(Point(x, y));
RGB图像像素点值获取
Vec3b intensity_src = src.at<Vec3b>(120, 200);
float blue = intensity_src.val[0];
float green = intensity_src.val[1];
float red = intensity_src.val[2];
我们将这些值输出可以得到下面的结果
修改像素点值
我们同样可以使用上面的获取像素点值的方式来修改对应的像素点值
gray_src.at<uchar>(y, x) = 50;
当我们运行如下代码:
for (int x=50;x<80;x++)
for(int y=50;y<80;y++)
{
gray_src.at<uchar>(y, x) = 50;
}
imshow("output",gray_src);
我们可以看到在对应图像的对应区域的像素值被改变(图中黑框):
应用实例之图像反转
反转部分实现代码
完整代码见文章末尾—建议使用完整代码进行学习
Mat dst; //定义新的 Mat对象dst
dst.create(src.size(), src.type()); //create一个大小类型和src图像一致的对象[对谁(src或gray_src)反转就创建和其大小和类型相同的空白图像]
for (int row = 0; row < height; row++) { //行扫描
for (int col = 0; col < width; col++) { //列扫描
if (dst.channels() == 1) { //当src图像为单通道(灰度图)时
int gray = gray_src.at<uchar>(row, col);
dst.at<uchar>(row, col) = 255 - gray;
}
else if (dst.channels() == 3) { 当src图像为三通道(BGR图)时
int b = src.at<Vec3b>(row, col)[0]; //获取B通道某点像素值
int g = src.at<Vec3b>(row, col)[1]; //获取B通道某点像素值
int r = src.at<Vec3b>(row, col)[2]; //获取B通道某点像素值
dst.at<Vec3b>(row, col)[0] = 255 - b; //对图像B通道某点像素值进行反转
dst.at<Vec3b>(row, col)[1] = 255 - g; //对图像G通道某点像素值进行反转
dst.at<Vec3b>(row, col)[2] = 255 - r; //对图像R通道某点像素值进行反转
}
}
}
imshow("output", dst); //显示反转之后的图像
waitKey(0); //等待按键后结束程序
这里对dst图像(BGR三通道)进行反转,运行结果为:
修改程序中的
dst.create(src.size(), src.type());
为
dst.create(gray_src.size(), gray_src.type());
可以对灰度图像进行反转,反转后结果为:
bitwise_not()函数实现图像反转
//上面的例子(求反转图片)可以用下面的函数来代替
bitwise_not(gray_src, dst); //对像素值进行反转操作
imshow("output", dst); //显示反转后的图像
小括号中第一个元素为反转前的图像,第二个元素为反转之后的图像
运行结果和上面一样:
对空白图像赋值【Scalar()函数】
//空白图像的赋值
Mat image0;
image0.create(src.size(), src.type());
image0 = Scalar(0, 0, 250);
imshow("output",image0);
首先创建一个空白Mat对象,并且使用create使其大小和类型和src图像一致(或其他大小和类型,同理)
接着使用Scalar()对其赋值,由于src为三通道图像,所以小括号中填三个值,分别对应通道B、G、R。
这里运行输出结果为:
感兴趣区域(ROI)的选择与提取
//ROI(感兴趣区域)的提取
Rect r(50,50, 150, 150);
Mat smallImg = src(r);
imshow("output",smallImg);
这里的Rect创建一个区域范围(x, y, x_width, y_height),前两个参数表示的时矩形区域开始的坐标,后两个参数分别表示x和y增加的坐标,即
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
运行结果为
右图为提取出来的ROI,范围为(50,50)到(200,200)
完整代码(详细注释)
每一部分结束都会加一个waitKey(0);
程序运行时,按下任意按键即可继续运行下一部分代码
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, gray_src; //创建Mat对象src保存bge格式的原图,gray_src保存cvtcolor后的gray灰度图
src = imread("A:/opencvproject/pikaqiu.jpg",IMREAD_COLOR); //读bgr格式的原图保存在src中
if (src.empty()){ //确保图像存在,并正确读入
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE); //创建输入图像窗口
imshow("input", src); //显示BGR格式的输入图像
cvtColor(src,gray_src,CV_BGR2GRAY); //格式转换BGR-->GRAY
int height = gray_src.rows; //获取灰度图的行数(和BGR格式的行数一致)
int width = gray_src.cols; //获取灰度图的列数(和BGR格式的列数一致)
namedWindow("output",CV_WINDOW_AUTOSIZE); //创建输出窗口
imshow("output", gray_src); //显示灰度图输出
cout << "rows is:" << height << "\n" << "cols is:" << width << endl; //打印灰度图的长宽
waitKey(0); //等待按键,按键之后开始下一步
//单通道像素值获取
Scalar intensity_gray = gray_src.at<uchar>(120,200); //获取灰度图的第 120 行,第 200 列的像素值
cout << "gray_src vaul of (120,200) =" << intensity_gray << endl; //打印获取到的像素值
//三通道(BGR)像素值获取
Vec3b intensity_src = src.at<Vec3b>(120, 200); //获取BGR图像的第 120 行,第 200 列的像素值
cout << "src vaul of (120,200) =" << intensity_src << endl; //打印获取到的像素值
int blue = intensity_src[0]; //分别获取像素值的B、G、R通道对应的值
int green = intensity_src[1];
int red = intensity_src[2];
cout << "blue vaul is:" << blue << endl; //分别打印对应通道的值
cout << "green vaul is:" << green << endl;
cout << "red vaul is:" << red << endl;
waitKey(0); //等待按键开始下一步
for (int x = 50; x < 80; x++) //上面获取到了对应像素点的值,下面开始用同样的方式修改像素点的值
for (int y = 50; y < 80; y++)
{
gray_src.at<uchar>(y, x) = 50; //修改GRAY灰度图50-80行和列围成的30*30的正方形的像素值为50
}
imshow("output", gray_src); //在output窗口显示修改后的图像
waitKey(0); //等待按键,按键后进行下一步
//下面用反转图像的例子来应用像素值的获取和修改
Mat dst; //定义新Mat对象dst
dst.create(gray_src.size(), gray_src.type()); //create一个大小类型和src图像一致的对象[对谁(src或gray_src)反转就创建和其大小和类型相同的空白图像]
for (int row = 0; row < height; row++) { //行扫描
for (int col = 0; col < width; col++) { //列扫描
if (dst.channels() == 1) { //当src图像为单通道(灰度图)时
int gray = gray_src.at<uchar>(row, col);
dst.at<uchar>(row, col) = 255 - gray;
}
else if (dst.channels() == 3) { 当src图像为三通道(BGR图)时
int b = src.at<Vec3b>(row, col)[0]; //获取B通道某点像素值
int g = src.at<Vec3b>(row, col)[1]; //获取B通道某点像素值
int r = src.at<Vec3b>(row, col)[2]; //获取B通道某点像素值
dst.at<Vec3b>(row, col)[0] = 255 - b; //对图像B通道某点像素值进行反转
dst.at<Vec3b>(row, col)[1] = 255 - g; //对图像G通道某点像素值进行反转
dst.at<Vec3b>(row, col)[2] = 255 - r; //对图像R通道某点像素值进行反转
}
}
}
imshow("output", dst); //显示反转之后的图像
waitKey(0); //等待按键后结束程序
//上面的例子(求反转图片)可以用下面的函数来代替
bitwise_not(gray_src, dst); //对像素值进行反转操作
imshow("output", dst); //显示反转后的图像
waitKey(0);
//空白图像的赋值
Mat image0; //创建一个新的Mat对象image0
image0.create(src.size(), src.type()); //其大小和类型与src一致
image0 = Scalar(0, 0, 250); //使用Scalar()对BGR三通道图像赋值
imshow("output",image0); //输出显示得到的图像
waitKey(0);
//ROI(感兴趣区域)的提取
Rect r(50,50, 150, 150); //选择一个矩形区域(50,50)-->(200,200)
Mat smallImg = src(r); //在src图像上提取对应区域
imshow("output",smallImg); //显示对应区域
waitKey(0);
return 0;
}