opencv-4学习(三)图像的基本操作

1、颜色处理

1.1、颜色模型转换

基本知识:有5种颜色模型,第一种是最常见的RGB模型,就是我们通常使用的红绿蓝三色素,同过不同比例的混合显现出不同色彩。第二种YUV颜色模型,一般是电视信号系统采取的颜色编码,Y表示像素亮度,U表示红色与亮度信号差值,V表示蓝色与亮度差值。第三种是HSV颜色模型,H是色度,S是饱和度,V是亮度。第四种是Lab颜色模型,L表示亮度,a和b是两个颜色通道,取值范围是-128到127,其中a通道由小到大颜色从绿变红,b通道有小到大颜色从蓝变黄。第五种是GRAY颜色模型。GRAY模型就是我们常说的灰度图像模型。取值范围0到255,颜色从黑变白。
在opencv中,颜色模型的转换很简单,通过cvtColor函数就能实现颜色模型转换。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	/*颜色模型转换*/
	//声明
	Mat yuv_i, hsv_i, lab_i, gray_i;
	//读取图片
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	//颜色模型转换
	cvtColor(im, yuv_i,COLOR_RGB2YUV);
	cvtColor(im, hsv_i, COLOR_RGB2HSV);
	cvtColor(im, lab_i, COLOR_RGB2Lab);
	cvtColor(im, gray_i, COLOR_RGB2GRAY);
	//显示图片
	imshow("原图", im);
	imshow("yuv", yuv_i);
	imshow("hsv", hsv_i);
	imshow("lab", lab_i);
	imshow("gray", gray_i);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行代码
在这里插入图片描述

1.2 多通道分离与合并

在opencv中,通过split函数分离多通道,通过merge函数合并多通道。
split(in,out);in是指待分离多通道图像,out是数组或者容器的mat类。
merge同理,与split不同的是,merge用数组时候需要通道数作为参数,如merge(in,3,out).而容器不用。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	/*多通道分离与合并*/
	//图像读取
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	//多通道分离
	vector<Mat> images;
	Mat im0,im1,im2;
	split(im, images);
	im0 = images.at(0);
	im1 = images.at(1);
	im2 = images.at(2);
	imshow("R通道", im0);
	imshow("G通道", im1);
	imshow("B通道", im2);
	//多通道合并
	cout << "图片大小:" << images[1].size() << endl;
	images[1] = Mat::zeros(images[1].size(), CV_8UC1);
	Mat result;
	merge(images,result);
	imshow("缺少G通道", result);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得:
在这里插入图片描述

2、像素处理

2.1、像素统计

最大值与最小值:minMaxLoc(im, &minv, &maxv, &minid, &maxid);
im为单通道矩阵。minv,maxv分别为通道的最大值与最小值。minid与maxid分别为矩阵中的位置,为point类型。
平均值与标准差计算:meanStdDev(im,my_mean,my_std);
im为图像,my_mean是平均值,my_std为标准差;

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	vector<Mat> images;
	Mat im0, im1, im2;
	split(im, images);
	im0 = images.at(0);
	im1 = images.at(1);
	im2 = images.at(2);
	double minv, maxv;
	Point minid, maxid;
	minMaxLoc(im0, &minv, &maxv, &minid, &maxid);
	cout << "最大值:" << maxv << "---位置:" << maxid << endl;
	cout << "最小值:" << minv << "---位置:" << minid << endl;
	Mat my_mean,my_std;
	meanStdDev(im,my_mean,my_std);
	cout << "平均值:" << my_mean << "---标准差:" << my_std<<endl;
	return 0;
}

运行得:
在这里插入图片描述

2.2、图像与图像间操作

两图像对应较小像素得到的图像:min(im1,im2,min_im),min_im是得到的图像。
两图像对应较大像素得到的图像:min(im1,im2,max_im),max_im是得到的图像。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//读取图片
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	//得到图片长宽
	int w=im.size().width;
	int h = im.size().height;
	//裁剪成两幅一样大的图片
	Mat im1, im2;
	Rect rect1(0, 0, w / 2, h);
	Rect rect2(w/2, 0, w / 2, h);
	im1 = im(rect1);
	im2 = im(rect2);
	//比较对应像素大小获得对应像素
	Mat min_im,max_im;
	min(im1, im2, min_im);
	max(im1, im2, max_im);
	imshow("min", min_im);
	imshow("max", max_im);
	waitKey(0);
	destroyAllWindows();
}

运行得:
在这里插入图片描述
两幅图像的逻辑操作:
进行的逻辑运算是从十进制转换成二进制进行。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	/*图像逻辑运算*/
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	Mat my_or, my_and, my_xor, my_not;
	bitwise_and(im, im, my_and);
	bitwise_or(im, im, my_or);
	bitwise_xor(im, im, my_xor);
	bitwise_not(im, my_not);
	imshow("and", my_and);
	imshow("or", my_or);
	imshow("xor", my_xor);
	imshow("not", my_not);
	waitKey(0);
	destroyAllWindows();
}

在这里插入图片描述

2.3、图像二值化

原理:比较简单,通过设置阈值得到二值图像。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	Mat im_b, im_bv;
	threshold(im, im_b, 125, 255, THRESH_BINARY);
	threshold(im, im_bv, 125, 255, THRESH_BINARY_INV);
	imshow("im_b", im_b);
	imshow("im_bv", im_bv);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

在这里插入图片描述

3、图像变换

3.1、图像连接

图像连接就是降两张具有相同高度或者相同宽度的图像连接起来。
opencv4中提供了两个函数用于图像连接,vconcat()函数用于实现图像的上下连接,hconcat()函数用于实现图像的左右连接。

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//读取图片
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	//把一张图片分成两份
	int w = im.size().width;
	int h = im.size().height;
	Mat im1, im2;
	Rect rect1(0, 0, w / 2, h);
	Rect rect2(w / 2, 0, w / 2, h);
	im1 = im(rect1);
	im2 = im(rect2);
	//图片连接
	Mat im_v, im_h;
	vconcat(im1, im2, im_v);
	hconcat(im1, im2, im_h);
	imshow("上下连接", im_v);
	imshow("左右连接", im_h);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得:
在这里插入图片描述

3.2、图像尺寸变换

在opencv4中提供resize()函数用于修改成指定尺寸。
调用格式resize(row_image,out_image,out_size,w_ratio,h_ratio,method)
row_image:输入的图像
out_image:输出的图像
out_size:改变后的图像的大小
w_ratio:w的比例因子,如果将水平轴变成原来的两倍,则赋值2
h_ratio:h的比例因子,同上
method:改变图像尺寸用的方法,比如缩小图像,就相当于一个下采样,要怎么下采样,比如扩大图像,就需要填充像素,该用什么方法填充像素。一般缩小用INTER_AREA,放大用双三次插值INTER_CUBIC

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//读取图像
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	//获取图像长宽
	int w = im.size().width;
	int h = im.size().height;
	Mat im_up, im_dn;
	//放大、缩小图像(改变图像尺寸)
	resize(im, im_up, Size(w * 2, h * 2), 0, 0, INTER_CUBIC);
	resize(im, im_dn, Size(w / 2, h / 2), 0, 0, INTER_AREA);
	imshow("放大图像", im_up);
	imshow("缩小图像", im_dn);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得
在这里插入图片描述

3.3、图像翻转变换

opencv4中使用flip()函数实现图像翻转。
调用格式:flip(row_image,out_image,method)
row_image:输入图像
out_image:输出图像
mehod:翻转方式,大于0表示绕y轴翻转,等于0表示按x轴翻转,小于0表示按x轴跟y轴翻转.

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//读取图像
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	Mat im_x, im_y, im_xy;
	//翻转图像
	flip(im, im_x, 0);
	flip(im, im_y, 1);
	flip(im, im_xy, -1);
	imshow("原图像", im);
	imshow("绕x轴旋转", im_x);
	imshow("绕y轴旋转", im_y);
	imshow("绕x,y轴旋转", im_xy);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

在这里插入图片描述

3.4、图像仿射变换

opencv4使用getRotationMatrix2D()函数计算旋转矩阵,getAffineTransform()通过三个对应点求变换矩阵,warpAffine()函数实现图像的仿射变换,仿射变换就是线性变换+平移,可以保证图像的平行线不变,面积的比值不变。。想仔细了解建议自行百度。
调用格式:
rotation=getRotationMatrix2D(center,angle,scale)
rotation=getAffineTransform(row_point,new_point)
warpAffine(row_image,out_image,rotation,size,flags,border_mode,border_value)
其中:
rotation:旋转矩阵,getRotationMatrix2D函数的返回值,是一个2×3的矩阵。
center:图像旋转的中心位置
angle:图像旋转角度,正值为逆时针旋转,单位为度。
scale:两个轴的比例因子,可以实现缩放,不缩放为1.
row_point:源图像中三个点的坐标
new_point:目标图像中三个点的对应坐标
row_image:原图像
out_image:输出图像
size:输出图像的大小
flags:插值方法标志
border_mode:像素边界外推方法标志
border_value:填充值,默认为0

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//读取图像
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	int w = im.size().width;
	int h = im.size().height;
	Point2f center(w / 2, h / 2);
	double angle = 60;
	Mat rotation = getRotationMatrix2D(center, angle, 1);
	Mat im_out1,im_out2;
	Point2f row_point[3], new_point[3];
	row_point[0] = Point2f(0, 0);
	row_point[1] = Point2f(0, h);
	row_point[2] = Point2f(w, 0);
	new_point[0] = Point2f(0.11*w, 0.2*h);
	new_point[1] = Point2f(0.15*w, 0.6*h);
	new_point[2] = Point2f(0.7*w, 0.3*h);
	Mat rotation2 = getAffineTransform(row_point, new_point);
	warpAffine(im, im_out1, rotation, Size(w, h));
	warpAffine(im, im_out2, rotation2, Size(w, h));
	imshow("原图像", im);
	imshow("仿射变换", im_out1);
	imshow("仿射变换2", im_out2);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得:
在这里插入图片描述

3.5、图像透视变换

透视变换就是将物体重新投影到新的成像平面,比如摄像机成像,就死透视变换,在opencv4中,使用getPerspectiveTransform函数和warpPerspective函数进行图像的透视变换。
调用格式:
ratation=getPerspectiveTransform(row_point,new_point,method)
warpPerspective(row_image,out_image,rotation,size,flags,border_mode,border_value)
其中:
row_point:原图像的四个像素坐标
new_point:目标图像的四个像素坐标
method:计算透视矩阵的方法
ratation:变换矩阵
row_image:输入图像
out_image:输出图像
size:输出图像大小
flags:插值方法标志
border_mode:像素边界外推方法标志
border_value:填充值,默认为0

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	//图像读取
	Mat im = imread("E:\\opencv_study\\opencv_study.png");
	int w = im.size().width;
	int h = im.size().height;
	Point2f row_image[4], new_image[4];
	row_image[0] = Point2f(0, 0);
	row_image[1] = Point2f(0, h);
	row_image[2] = Point2f(w, 0);
	row_image[3] = Point2f(w, h);
	new_image[0] = Point2f(0.2*w, 0.2*h);
	new_image[1] = Point2f(0.2*w, 0.6*h);
	new_image[2] = Point2f(0.7*w, 0.3*h);
	new_image[3] = Point2f(0.8*w, 0.8*h);
	Mat rotation = getPerspectiveTransform(row_image, new_image);
	Mat im_out;
	warpPerspective(im, im_out, rotation, Size(w, h));
	imshow("原图像", im);
	imshow("透视变换", im_out);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得:
在这里插入图片描述

4、绘制几何图形

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;

int main() {
	Mat im = Mat::zeros(Size(512, 512), CV_8UC3);
	circle(im, Point(50, 50),25, Scalar(255, 255 ,0), -1);//绘制实心圆
	circle(im, Point(50, 20), 25, Scalar(255, 255, 0), 3);//绘制空心圆
	line(im, Point(100, 100), Point(200, 100), Scalar(255, 255, 255), 2, LINE_4);//绘制直线
	ellipse(im, Point(300, 250), Size(100, 70), 0, 0, 360, Scalar(0, 0, 255), -1);//绘制椭圆
	rectangle(im, Rect(200, 150, 100, 60), Scalar(0, 255, 255), -1);//绘制矩形
	Point p[5];
	p[0] = Point(350, 80);
	p[1] = Point(460, 90);
	p[2] = Point(500, 170);
	p[3] = Point(420, 190);
	p[4] = Point(340, 140);
	const Point *pts[1] = { p };
	int npts[] = { 5 };
	fillPoly(im,pts,npts,1, Scalar(0, 255, 255), 8);//绘制多边形
	putText(im, "TEST", Point(100, 100), 2, 1, Scalar(255, 0, 255));//绘制文字
	imshow("图像显示", im);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得:
在这里插入图片描述

5、窗口交互操作

交互操作主要有两个,一个是图像窗口滑动,一个是鼠标响应,在opencv4中,使用createTrackbar函数实现图像窗口滑动,使用setMouseCallback函数实现鼠标响应。
调用格式:
createTrackbar(trackname,winname,value,max_value,callback,user_data)
setMouseCallback(winname,mouse_callback,mouse_data)
其中:
trackname:滑动条名称
winname:窗口名称
value:指向整数变量的指针,该指针指向的值反映滑块的位置,创建后,滑块位置由此变量定义。
max_value:滑动的最大值
callback:回调函数
user_data:传递给回调函数的可选参数
mouse_callback:鼠标响应的回调函数
mouse_data:传递给鼠标响应回调函数的可选参数

# include<iostream>
#include<opencv.hpp>

using namespace std;
using namespace cv;
int value;
Mat im, im2;
Point prepoint;
static void callback(int ,void*) {
	float a = float(value) / 100;
	im2 = im * a;
	imshow("图像显示", im2);
}
static void mouse(int event, int x, int y, int flags, void *) {
	if (event == EVENT_MOUSEMOVE && (flags&EVENT_FLAG_LBUTTON)) {
		im.at<Vec3b>(y, x) = Vec3b(0, 0, 255);
		im.at<Vec3b>(y+1, x) = Vec3b(0, 0, 255);
		im.at<Vec3b>(y, x+1) = Vec3b(0, 0, 255);
		im.at<Vec3b>(y-1, x) = Vec3b(0, 0, 255);
		im.at<Vec3b>(y, x-1) = Vec3b(0, 0, 255);
		imshow("图像显示", im);
	}
}
int main() {
	im = imread("E:\\opencv_study\\opencv_study.png");
	value = 100;
	imshow("图像显示", im);
	createTrackbar("亮度百分比", "图像显示", &value, 600, callback, 0);
	setMouseCallback("图像显示", mouse, 0);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

运行得,按住左键可在图上画图案。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值