opencv c++入门(1-30)持续更新

图像加载与显示

读取图像 imread() 返回一个 **Mat **对象;
展示图像 imshow();

  • waitKey(int num)num = 0 表示等待(阻塞),num > 0 停顿num毫秒;
  • cv::namedWindow("窗口名");: 有其他重载和参数:如下
  • cv::imread("图片路径",flag);:第二个参数是一个 flag,指定了应该读取图像的方式;( 只支持8位或浮点数类显示,其它类型有点问题 ) 例子如下代码;
    1. IMREAD_COLOR:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志
    2. IMREAD_GRAYSCALE:以灰度模式加载图像
    3. IMREAD_UNCHANGED:加载图像,包括 alpha (透明)通道
  • ``
#include <iostream>
#include "opencv2/opencv.hpp"

int main() {
	//cv::IMREAD_GRAYSCALE 图片显示为灰色
	cv::Mat img = cv::imread("cfy.jpg",cv::IMREAD_GRAYSCALE);
	//cv::WINDOW_FREERATIO  可以调整窗口大小
	cv::namedWindow("img",cv::WINDOW_FREERATIO);
	cv::imshow("img", img);
	cv::waitKey(0);
	return 0;
} 
  • img.depth():返回各个图片深度代表的枚举值
  • img.empty():是否为空白

以上img均为cv::Mat 类型

图像色彩空间转换

  • void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );色彩空间转换函数;函数参数解释:
  1. src(source):输入的源图像。为矩阵形式。
  2. dst(destination):输出的目标图像,即经过色彩转后我们需要得到的图像。也为矩阵形式。
  3. code:颜色空间转换的标识符,表示我们所要进行空间转换的结果。
    code的参数多达200多,在此列举一些常用的参数,更多参数请查阅opencv官方文档
空间转换标识符code
BGR——灰度COLOR_BGR2GRAY6
RGB——灰度COLOR_RGB2GRAY7
灰度——RGB/BGRCOLOR_GRAY2RGB = COLOR_GRAY2BGR8
BGR——HSVCOLOR_BGR2HSV40
RGB——HSVCOLOR_RGB2HSV41
HSV——BGRCOLOR_HSV2BGR54
HSV——RGBCOLOR_HSV2RGB55
  • 注意!此处有知识点!在opencv中彩色图像(RGB图像)按照BGR顺序进行存储。所以以彩色图像为源图像进行颜色空间转换时,注意是“BGR2”
  1. dstCn:目标图像的通道数。默认值为0,表示目标图像取源图像的通道数 。
void QuickDemo::colorSpace_Demo(Mat &image)
{
	Mat gray, hsv;
	cvtColor(image,hsv,COLOR_RGB2HSV);
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("HSV",hsv);
	imshow("灰度", gray);
	imwrite("B:/c++/opencv_object/opencv1/save_img/hsv.png",hsv);
	imwrite("B:/c++/opencv_object/opencv1/save_img/gray.png", gray);
}

摘自:初学opencv c++学习笔记(二)图像空间色彩转换cvtColor()

图像对象的创建与赋值

在这里插入图片描述

创建空白mat
Mat m3 = Mat::zeros(Size(8,8),CV_8UC3);
std::cout << "width: " << m3.cols << " height: " << m3.rows << std::endl;
std::cout<<" channels(通道数): " << m3.channels() << std::endl;
std::cout << m3 << std::endl;
  • 参数:CV_8UC3
  • 在这里插入图片描述
    通道数为:3; 结果:每个像素点占三个数据,则一行宽度为 像素宽度 * 通道数;
  • 还可以利用 Mat m3 = Mat::ones(Size(8,8),CV_8UC1);初始化各个像素点为1;如果使用3通道则会造成只初始化一个通道如图:在这里插入图片描述
赋值
  • 可以直接赋值但是只会赋值第一个通道
Mat m3 = Mat::zeros(Size(8,8),CV_8UC3);
m3 = 127;
  • 在知道通道数时,利用m3 = Scalar(123,111,211); 赋值;
void QuickDemo::mat_creation_Demo(Mat& image)
{

	//创建空白
	Mat m3 = Mat::zeros(Size(400,400),CV_8UC3);
	m3 = Scalar(123,111,211);//赋值最大为255
	imshow("图像", m3);
}

  • 还可以Mat m4 = m3;但只拷贝了矩阵头部,共用一块数据;
Mat m3 = Mat::zeros(Size(400,400),CV_8UC3);
m3 = Scalar(255,0,255);//赋值最大为255
//imshow("图像", m3);
Mat m4 = m3;
m4 = Scalar(0,255,255);
imshow("图像", m3);
std::cout << m3 << std::endl;
复制 与 克隆
  • 利用复制 和克隆会产生一个新的数据部分与原来不发生关系
void QuickDemo::mat_creation_Demo(Mat& image)
{
	Mat m1, m2;
	//克隆
	m1 = image.clone();
	//拷贝
	image.copyTo(m2);
}

图像像素的读写操作

  • Vec3b存储3通道像素对象
基于数组下标
void QuickDemo::pixel_visit_Demo(Mat& image)
{
	int width = image.cols;
	int hight = image.rows;
	//通道数
	int dims = image.channels();
	for (int row = 0; row < hight; 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];

			}
		}
	}
	imshow("读写展示",image);
}
基于指针
  • 速度更快
void QuickDemo::pixel_visit_Demo(Mat& image)
{
	int width = image.cols;
	int hight = image.rows;
	//通道数
	int dims = image.channels();
	for (int row = 0; row < hight; row++) {
		uchar* current_row = image.ptr<uchar>(row);
		for (int col = 0; col <width; col++) {
			if (dims == 1) {
				//单通道像素点(灰度图像)
				int pv = *current_row;
				*current_row++ = 255 - pv;
			}
			if(dims==3){
				//彩色图像(三通道)
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			}
		}
	}
	imshow("读写展示",image);
}

图像像素基本操作

  • 加减除均可以
void QuickDemo::operators_Demo(Mat& image)
{
	Mat m;
	m = image + Scalar(20,20,20);
	imshow("加法操作",m);
}
  • 乘法
void QuickDemo::operators_Demo(Mat& image)
{
	Mat result;
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(2, 2, 2);
	multiply(image, m, result);
	imshow("乘法操作",result);
}
  • saturate_cast<uchar>主要是为了防止颜色溢出操作;详解
void QuickDemo::operators_Demo(Mat& image)
{
	Mat result = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(2, 2, 2);
	multiply(image, m, result);
	imshow("乘法操作",result);

	int width = image.cols;
	int hight = image.rows;
	//通道数
	int dims = image.channels();
	for (int row = 0; row < hight; row++) {
		for (int col = 0; col < width; col++) {
			Vec3b p1 = image.at<Vec3b>(row, col);
			Vec3b p2 = m.at<Vec3b>(row, col);
			result.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
			result.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
			result.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
		}
	}
	imshow("读写展示", image);
}
api函数
  • add加法
  • subtract减法
  • divide除法
  • multiply乘法

滚动条操作

调整图像亮度
  • 以下:createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track); 利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
Mat dst, m, src;
//当前亮度(进度条当前值)
int lightness = 50;
static void on_track(int, void*) {
	m = Scalar(lightness,lightness,lightness);
	add(src,m,dst);
	imshow("亮度调整",dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
	dst = Mat::zeros(image.size(), image.type());
	m = Mat::zeros(image.size(), image.type());
	src = image;
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	int max_value = 100;
	//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
	//类似于信号与槽
	createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track);
	//当前没用
	on_track(50,0);
}
参数传递、亮度、对比度
  • 函数指针
  • static在修饰局部变量和函数的作用
  • userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
  • value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
//opencv源代码函数指针
typedef void (*TrackbarCallback)(int pos, void* userdata);
//opencv源代码函数声明
CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,int* value, int count,TrackbarCallback onChange = 0,void* userdata = 0);
  • void* userdata 无类型指针传递参数
static void on_track(int pos, void* userdata ) {
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(pos,pos,pos);
	add(image,m,dst);
	imshow("亮度调整",dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	int max_value = 100;
	//当前亮度(进度条当前值)
	int lightness = 50;
	//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
	//类似于信号与槽
	//userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
	//value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
	createTrackbar("value bar:", "亮度调整", &lightness, max_value,on_track,(void*)&image);
	//on_track(50,&image); 可以省略
}

  • 亮度与对比度
  • 注意: createTrackbar函数窗口名字必须有创建指定否则会出现空指针;imshow的窗口名称如果已有则用已有,否则创建新的窗口,如下两个滚动条改变都展现在“亮度调整”窗口
  • addWeighted()
static void on_lightness(int pos, void* userdata) {
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	//add(image, m, dst);
	addWeighted(image, 1.0, m, 0, pos, dst);
	imshow("亮度调整", dst);
}
static void on_contrast(int pos, void* userdata) {
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	//第一个的权重 通过进度条来改变
	double contrast = pos / 100.0;
	addWeighted(image,contrast, m,0.0,0, dst);
	imshow("亮度调整", dst);
}
void QuickDemo::tracking_bar_Demo(Mat& image)
{
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	int max_value = 100;
	//当前亮度(进度条当前值)
	int lightness = 50;
	int contrast = 100;
	//利用引用通过进度条滑动改变lightness,同步调用on_track进行亮度改变。
	//类似于信号与槽
	//userdata按原样传递给回调的用户数据。它可以用来处理trackbar事件而不使用全局变量。
	//value可选指针,指向一个整型变量,其值反映滑块的位置。创建后,滑块位置由该变量定义。
	createTrackbar("value bar:", "亮度调整", &lightness, max_value, on_lightness,(void*)&image);
	createTrackbar("Contrast bar:", "亮度调整", &contrast, 200 , on_contrast,&image);
	on_lightness(50,&image); 
}

键盘响应操作

  • char c = cv::waitKey(时间); 在等待时间按键返回按键键值;
void QuickDemo::key_Demo(Mat& image)
{
	Mat dst = Mat::zeros(image.size(),image.type());
	//使用英文输入法
	while (true) {
		//等待输入
		int c = waitKey(0);
		if (c == 27) {
			std::cout << "key = Esc" << std::endl;
			break;
		}
		if (c == 49) {
			std::cout << "key = 1" << std::endl;
			cvtColor(image, dst, COLOR_BGR2GRAY);
		}
		if (c == 50) {
			std::cout << "key = 2" << std::endl;
			cvtColor(image, dst, COLOR_BGR2HSV);
		}
		if (c == 51) {
			std::cout << "key = 3" << std::endl;
			dst = Scalar(50, 50, 50);
			add(image, dst, dst);
		}
		imshow("键盘响应", dst);
	}
}

opencv自带颜色表操作

  • 源函数void applyColorMap(InputArray src, OutputArray dst, int colormap);
  • 代码
void QuickDemo::color_style_demo(Mat& image) {
//颜色表数组
	int colormap[] = {COLORMAP_AUTUMN,COLORMAP_BONE,COLORMAP_JET,COLORMAP_WINTER,
		COLORMAP_RAINBOW,COLORMAP_OCEAN,COLORMAP_SUMMER,COLORMAP_SPRING,
		COLORMAP_COOL,COLORMAP_HSV,COLORMAP_PINK,COLORMAP_HOT,
		COLORMAP_PARULA,COLORMAP_MAGMA,COLORMAP_INFERNO,COLORMAP_PLASMA,
		COLORMAP_VIRIDIS,COLORMAP_CIVIDIS,COLORMAP_TWILIGHT,COLORMAP_TWILIGHT_SHIFTED,
		COLORMAP_TURBO,COLORMAP_DEEPGREEN
	};
	Mat dst;
	int index = 0;
	while (true) {
		int c = waitKey(500);
		if (c == 27) {//key:esc
			break;
		}
		applyColorMap(image, dst, colormap[index % 22]);
		//std::cout <<index<<"," << index % 22 << std::endl;
		index++;
		imshow("颜色风格", dst);
	}
}

图像像素的逻辑操作

  • rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0); 绘制矩形
  • 位操作
void QuickDemo::bitwise_Demo(Mat& image) {
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
	//第三个参数小于0为填充;大于0为绘制;
	//抗锯齿能力:LINE_AA > LINE_8 > LINE_4
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
	imshow("m1", m1);
	imshow("m2", m2);
	Mat dst;
	//bitwise_and(m1, m2, dst);//Scalar(0,255,0
	//bitwise_or(m1, m2, dst);
	bitwise_not(image, dst); // 另一种取反方式:Mat dst = ~image;
	//bitwise_xor(m1, m2, dst);
	imshow("位操作", dst);
}


通道分离与合并

  • CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts,const int* fromTo, size_t npairs);通道换位
  • mixChannels
void QuickDemo::split_merge_Demo(Mat& image) {
	std::vector<Mat>mv;
	split(image, mv);
	imshow("b", mv[0]);
	imshow("g", mv[1]);
	imshow("r", mv[2]);

	Mat dst;
	//三个通道组成各种颜色,如下eg:蓝色通道为0,则为绿色+红色=黄色
	mv[0] = 0;
	//mv[1] = 0;
	//mv待合并矩阵的输入向量;mv中的所有矩阵必须具有相同的大小和相同的深度。
	//dst输出与mv[O]相同大小和深度的数组;通道数将是矩阵数组中通道的总数。
	merge(mv, dst);
	imshow("dst", dst);
	//转换数组:两个为一组,第0通道到第2通道(0->2)还有(1->1),(2->0)
	int from_to[] = { 0,2,1,1,2,0 };
	mixChannels(&image, 1, &dst, 1, from_to, 3);
	imshow("通道混合", dst);
}

图像色彩空间转换

  • hsv颜色值范围表

  • 在这里插入图片描述

  • inRange() 主要是将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0),该功能类似于之间所讲的双阈值化操作。

  • copyTo()

void QuickDemo::inrange_Demo(Mat& image) {
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	//(35, 43, 46)绿色最小值
	/*inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);*/
	//将在两个阈值内的像素值设置为白色(255),而不在阈值区间内的像素值设置为黑色(0)
	inRange(hsv, Scalar(0, 0, 221), Scalar(180, 30, 255), mask);
	//抠出人像黑色区域
	//imshow("mask", mask);
	//创建空白图像
	Mat redback = Mat::zeros(image.size(), image.type());
	//设为红色
	redback = Scalar(40, 40, 200);
	//取反黑白互换 人像位置为黑,其余为白。
	bitwise_not(mask, mask);
	imshow("mask", mask);
	//mask是罩子,把人像通过mask抠出复制到readback
	image.copyTo(redback, mask);
	imshow("roi", redback);
}

图像像素值统计

  • minMaxLoc()用于找到一个多维数组中的最小值和最大值,以及它们的位置。(传入的值必须是单通道的)
  • meanStdDev()OpenCV计算图像的平均值和标准差的函数meanStdDev函数的使用
void QuickDemo::pixel_statistic_Demo(Mat& image) {
	//最大小值
	double minv, maxv;
	//最大小值位置
	Point minloc, maxloc;
	//cvtColor(image, image,COLOR_BGR2GRAY);
	std::vector<Mat>mv;
	split(image, mv);
	for (int i = 0; i < image.channels(); i++) {
		minMaxLoc(mv[i], &minv, &maxv, &minloc, &maxloc, Mat());
		std::cout << "min value:" << minv << "  max value:" << maxv << std::endl;
	}
	Mat mean, stddev;
	meanStdDev(image, mean, stddev);
	std::cout << "mead:" << mean << "  stddev:" << stddev << std::endl;
}

图像几何形状绘制

cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int lineType=8, int shift=0)
  • 绘制结果:
  • 绘制结果
void QuickDemo::drawing_demo(Mat& image) {
	//定义矩形
	Rect rect;
	rect.x = 100;
	rect.y = 100;
	rect.width = 50;
	rect.height = 50;
	//绘制矩形
	rectangle(image, rect, Scalar(0, 0, 255), -1, 8, 0);
	//绘制圆
	circle(image, Point(50, 50), 45, Scalar(0, 255, 0), 1, 8, 0);
	//绘制线
	line(image, Point(50, 50), Point(100, 100), Scalar(0, 255, 0), 2, 8, 0);
	//椭圆
	RotatedRect rrt;
	rrt.center = Point(100, 100);
	rrt.size = Size(100, 50);
	rrt.angle = 0.0;
	//绘制椭圆
	//ellipse(image, rrt, Scalar(255, 255, 0), 2, 8);
	Mat bg = Mat::zeros(image.size(), image.type());
	Mat dst;
	//绘制为类似于遮盖的图片 结果图如上述图片‘绘制图形’
	circle(bg, Point(100, 200), 100, Scalar(255, 0, 0), -1, 8, 0);
	addWeighted(image, 0.7, bg, 0.3, 0, dst);
	imshow("绘制演示", dst);
}

随机数与随机颜色

void QuickDemo::random_drawing() {
	//创建画布
	Mat bg = Mat::zeros(Size(600, 600), CV_8UC3);
	int w = bg.cols;
	int h = bg.rows;
	//产生随机数
	RNG rng(12345);
	while (true) {
		int c = waitKey(1000);
		if (c == 27) {
			break;
		}
		//产生一个{rng.uniform(a, b);}a和b之间的随机数
		int x1 = rng.uniform(0, w);
		int y1 = rng.uniform(0, h);
		int x2 = rng.uniform(0, w);
		int y2 = rng.uniform(0, h);
		int b = rng.uniform(0, 255);
		int g = rng.uniform(0, 255);
		int r = rng.uniform(0, 255);
		bg = Scalar(0, 0, 0);
		line(bg, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 2, 8, 0);
		imshow("随机绘制", bg);
	}
}

多边形填充与绘制

void QuickDemo::polyline_drawing_demo() {
	Mat bg = Mat::zeros(Size(512, 512), CV_8UC3);
	Point p1(100, 100);
	Point p2(350, 100);
	Point p3(400, 280);
	Point p4(320, 480);
	Point p5(80, 400);
	std::vector<Point> pts;
	pts.push_back(p1);
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);
	//在图像上绘制带填充效果的多边形。
	//fillPoly(bg, pts, Scalar(255, 0, 0), 8, 0);
	// 绘制多边形,不能进行填充
	//polylines(bg, pts, true, Scalar(0, 0, 255), 2, LINE_AA, 0);
	std::vector<std::vector<Point>> cnts;
	cnts.push_back(pts);
	drawContours(bg, cnts, -1, Scalar(0, 255, 0), 2);
	imshow("多边形绘制", bg);
}

鼠标操作与响应

  • 源函数:CV_EXPORTS void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);

  • 回调函数格式:typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);

    • event 是 CV_EVENT_* 变量之一,CV_EVENT 见下表;
    • x 和 y 是鼠标在图像坐标系的坐标(不是窗口坐标系);
    • flags 是 CV_EVENT_FLAG 的组合;
    • param 是用户定义的传递到 setMouseCallback 函数调用的参数。
  • event 具体说明如下:

枚举值代表内容
EVENT_MOUSEMOVE0滑动
EVENT_LBUTTONDOWN1左键点击
EVENT_RBUTTONDOWN2右键点击
EVENT_MBUTTONDOWN3中键点击
EVENT_LBUTTONUP4左键放开
EVENT_RBUTTONUP5右键放开
EVENT_MBUTTONUP6中键放开
EVENT_LBUTTONDBLCLK7左键双击
EVENT_RBUTTONDBLCLK8右键双击
EVENT_MBUTTONDBLCLK9中键双击
  • flags 具体说明如下:
枚举值代表内容
EVENT_FLAG_LBUTTON1左键拖曳
EVENT_FLAG_RBUTTON2右键拖曳
EVENT_FLAG_MBUTTON4中键拖曳
EVENT_FLAG_CTRLKEY8(8~15)按 Ctrl 不放
EVENT_FLAG_SHIFTKEY16(16~31)按 Shift 不放
EVENT_FLAG_ALTKEY32(32~39)按 Alt 不放
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_drawing(int event, int x, int y, int flags, void* userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {
		//按下鼠标位置
		sp.x = x;
		sp.y = y;
		std::cout << "start point:" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {
		//抬起鼠标位置
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx >= 0 && dy > 0) {
			Rect box(sp.x, sp.y, dx, dy);
			temp.copyTo(image);
			imshow("截取ROI", image(box));
			rectangle(image, box, Scalar(0, 255, 0), 2, 8);
			imshow("鼠标绘制", image);
			sp.x = -1;
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 0 && sp.y > 0) {
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx >= 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(image);
				rectangle(image, box, Scalar(0, 255, 0), 2, 8);
				imshow("鼠标绘制", image);
			}
		}
	}
}

void QuickDemo::mouse_drawing_demo(Mat& image) {
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	//回调函数 类似与信号与槽
	setMouseCallback("鼠标绘制", on_drawing, (void*)(&image));
	imshow("鼠标绘制", image);
	temp = image.clone();
}


图像像素类型转换与归一化

1、函数原型

void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())

2.函数作用
归一化数据。该函数分为范围归一化与数据值归一化。(Normalizes the norm or value range of an array.)
3.参数说明

  • src 输入数组;

  • dst 输出数组,数组的大小和原数组一致;

  • alpha 1,用来规范值,2.规范范围,并且是下限;

  • beta 只用来规范范围并且是上限;

  • norm_type 归一化选择的数学公式类型;
    在这里插入图片描述
    在这里插入图片描述

  • dtype 当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;

  • mark 掩码。选择感兴趣区域,选定后只能对该区域进行操作。
    4.归一化选择的数学公式类型介绍(norm_type)
    在这里插入图片描述

5.举例说明:
src={10,23,71}

NORM_L1运算后得到 dst={0.096,0.221,0.683}

NORM_INF运算后得到 dst={0.141,0.324,1}

NORM_L2运算后得到 dst={0.133,0.307,0.947}

NORM_MINMAX运算得到 dst={0,0.377,1}

6.范围归一化与值归一化的区别
区别一:范围归一化使用的是如下式子,设范围为【0,255】

即把src缩放到【0,255】这个范围内,并不使用上面的4个公式去解。

区别二:使用范围归一化时,beta必有值不等于0

cv::normalize(a, a, 1,0, cv::NORM_MINMAX);

cv::normalize(a, a, 0,255, cv::NORM_MINMAX);
案例
void QuickDemo::norm_demo(Mat& image) {
	Mat dst;
	std::cout << image.type() << std::endl;
	//转换为浮点防止归一化由于类型转换无法显示后无法显示
	image.convertTo(image, CV_32F);
	std::cout << image.type() << std::endl;
	normalize(image, dst, 1.0, 0, NORM_MINMAX);
	std::cout << dst.type() << std::endl;
	imshow("图像数据归一化", dst);
}

图像放缩与差值

void QuickDemo::resize_demo(Mat& image) {
	Mat zoomin, zoomout;
	int h = image.cols;
	int w = image.rows;
	resize(image, zoomin, Size(w / 1.5, h / 1.5), 0, 0, INTER_LINEAR);
	resize(image, zoomout, Size(w * 1.2, h * 1.2), 0, 0, INTER_LINEAR);
	imshow("缩小", zoomin);
	imshow("放大", zoomout);
}

图像翻转与旋转

图像翻转
void QuickDemo::flip_demo(Mat& image) {
	Mat dst;
	// 0以x为轴镜像(上下),1以y轴镜像(左右),-1以x=y为轴镜像(相当于旋转180°)
	flip(image, dst, 1);
	imshow("图像翻转", dst);
}
图像旋转
  • getRotationMatrix2D()

  • 参数列表:

    • 旋转中心
    • 旋转角度
    • 旋转后的缩放比例
  • 构造矩阵利用getRotationMatrix2D() 构造如图:
    在这里插入图片描述

  • 则旋转角度:

double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
	M.at<double>(0, 2) += (nw / 2 - w / 2);
	M.at<double>(1, 2) += (nh / 2 - h / 2);
  • 函数原型
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
                              InputArray M, Size dsize,
                              int flags = INTER_LINEAR,
                              int borderMode = BORDER_CONSTANT,
                              const Scalar& borderValue = Scalar());
  • 参数列表
    • SRC输入图像。
    • DST输出图像,大小为dsize,类型与SRC相同。
    • M 变换矩阵
    • dsize输出图像大小。
    • borderMode像素外推方法;当borderMode=#BORDER_TRANSPARENT时,表示目标图像中对应于源图像中“离群值”的像素不被函数修改。
    • borderValue在边界不变的情况下使用的值;
案例
void QuickDemo::rotate_demo(Mat& image) {
	Mat M, dst;
	int w = image.cols;
	int h = image.rows;
	//获取变换矩阵
	M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
	double cos = abs(M.at<double>(0, 0));
	double sin = abs(M.at<double>(0, 1));
	int nw = w * cos + h * sin;
	int nh = w * sin + h * cos;
	M.at<double>(0, 2) += (nw / 2 - w / 2);
	M.at<double>(1, 2) += (nh / 2 - h / 2);
	warpAffine(image, dst, M, Size(nw,nh ), INTER_LINEAR, 0, Scalar(0, 255, 0));
	imshow("旋转", dst);
}

资料

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值