(一)opencv读取显示图片
这个吧,真的就算是opencv中的hello world了,基本上都知道是imread()这个函数,但是这个函数中的参数,在不同情况下的使用,还是略有讲究的,需要大家在学习的时候有所注意。
如果你只需要读入一张“常规的”图片(比如3通道8位,或是3通道24位,又或是一张灰度图),其实直接在“”中写入绝对地址或者相对地址即可。
但如果你是将一个文件夹内的所有图片循环读入做处理,就肯定不能这些写参数了,你需要一个字符串变量去保存你的图片名,字符串中的内容需要有所迭代增加,这时括号中的参数则直接是你所定义的字符串变量。通常会是
imread(filename);
再其他一些情况中,imread有两个参数,除了第一个参数是你所读入的图片名以外,还有第二个参数,其主要目的是对图片的类型做解释,比如:
imread("你的图片",1);
此时1代表读入彩色图像,0代表读入灰度图像。因为imread读进来的图像默认是3通道Mat类型的BGR色彩空间图像,所以如果你想要读入4通道的图像,可以写成
imread("你的图片名称",IMREAD_UNCHANGED);
如果你要读入的是其他色彩空间的图像,则可以写成
imread("你的图片名",IMREAD_ANYCOLOR);
再加入图像之后,你还可以为你的程序做一段容错处理的判断,查看图片是否读入进来,避免程序崩溃
if(image.empty())
{
cout<<"could not found this picture"<<endl;
return -1;
}
显示图片是依靠imshow函数,基本用法如下:
imshow("窗口名",image);
但有时图片过大单纯依靠imshow会显示不全图片,这时你需要用到namedwindow()函数,常规使用是
namedwindow("窗口名",WINDOW_FREERATIO);//第二个参数表示自由调整大小,可以按比例拉伸显示
imshow("窗口名",image);//两个窗口名需要保持一致
(二)基础色彩空间转换
如果你只是对常规的图像做色彩空间转换,可以借助cvtColor()这个函数,这个函数的使用也比较简单
cvtColor(Mat input, Mat output, BGR2HSV);//第三个参数是从什么色彩空间转换到什么色彩空间
(三)图像对象的创建与赋值
这个也可以直接看代码讲,你需要创建一个Mat类型的变量,zeros函数表示你创建出来的空白图像中的每个像素值都是0,第一个参数表示尺寸大小,第二个参数则是图像类型。第二种写法则是创建了一个每个像素值都是1的图像,它的大小和类型都与image图像相同,这种方式通常可以用作复制一张空白图像做处理,当然zeros用的更多。
Mat img = Mat::zeros(Size(8,8),CV_8UC1);//8位的无符号的,1表示单通道
Mat img = Mat::ones(image.size(),image.type());
对于给图像各个像素赋值,在3通道图像时,则需要对一个像素的三个通道都进行赋值,如果你读入的是灰度图像,则像第二行一样只需要一个参数去进行赋值
img = Scalar(0,127,127);
img = Scalar(255);
(四)图像像素的读写操作
对于图像每个像素的读写就需要用到循环遍历啦,你可以首先获取到图像的长宽(因为我自己总记不清cols和rows哪个是行哪个是列。。。尴尬,英语太差),然后对整幅图像进行遍历,记得要先列再行,进入第二层循环后,你可以对图像做个判断,核心的代码是
int pv = image.at<uchar>(row, col);
这句,at函数用来获得图像的某个像素点,row和col用来做角标定位像素点,读取出来的像素点的值被赋值给pv这个整型变量。下面的代码是读取后对它做了个反色处理。
void QuickDemo::pixel_visit_demo(Mat image)
{
int width = image.cols;
int height = image.rows;
int dims = image.channels();
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
if (dims == 1)//灰度图
{
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = 255 - pv;
}
if (dims == 3)//彩色图
{
Vec3b bgr = image.at<Vec3b>(row, col);
image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}
namedWindow("像素读写",WINDOW_FREERATIO);
imshow("像素读写",image);
}
(五)图像像素的算术操作
下面是展示了对图像像素进行乘法和加法运算,一种直接调用opencv中的api函数,一种是我们自己写。首先是创建了两个空白图像用来与原图像进行运算,给m图像进行了赋值,调用multiply函数进行了乘法运算。dst是运算后的结果图像。
void QuickDemo::operators_demo(Mat image)
{
Mat dst = Mat::zeros(image.size(),image.type());
Mat m = Mat::zeros(image.size(), image.type());
m = Scalar(2,2,2);
multiply(image,m,dst);
namedWindow("*",WINDOW_FREERATIO);
imshow("*",dst);
int width = image.cols;
int height = image.rows;
int dims = image.channels();
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
/*
if (dims == 1)//灰度图
{
int pv = image.at<uchar>(row, col);
image.at<uchar>(row, col) = 255 - pv;
}
*/
if (dims == 3)//彩色图
{
Vec3b p1 = image.at<Vec3b>(row, col);
Vec3b p2 = m.at<Vec3b>(row, col);
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
}
}
}
namedWindow("add",WINDOW_FREERATIO);
imshow("add",dst);
//有opencv 现成的api 函数就尽量直接调
(六)键盘响应操作
其实也挺简单的,和之前讲的东西结合了一点,只需要定义一个字符变量,然后让他在持续的循环中等待键盘中的某个键值就好。注意写循环要留退出方式!
void QuickDemo::key_demo(Mat image)
{
Mat dst = Mat::zeros(image.size(), image.type());
while (true)
{
char c = waitKey(100);
if (c == 's')
{
break;
}
if (c == 'q')
{
cvtColor(image,dst,COLOR_BGR2GRAY);
}
if (c == 'w')
{
cvtColor(image,dst,COLOR_BGR2HSV);
}
if (c == 'e')
{
dst = Mat::zeros(image.size(), image.type());
dst = Scalar(40,50,60);
add(image,dst,dst);
}
namedWindow("dst", WINDOW_AUTOSIZE);
imshow("dst", dst);
}
}