Opencv视觉处理(C++)语法学习图像的算术与逻辑运算

Posted Lumxi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Opencv视觉处理(C++)语法学习图像的算术与逻辑运算相关的知识,希望对你有一定的参考价值。

通过设定Scalar算子的算术运算操作

void QuickDemo::operator_demo(Mat& img)
{
	//演示画布任意操作
	Mat dst;
	dst = img + Scalar(50, 50, 50);//这样加法的操作之后会发现图片会亮一些 
    /*
	imshow("src", img);
	imshow("dst", dst);
	*/
	dst = img - Scalar(50, 50, 50);//这样减法的操作之后会发现图片会亮一些 
	//dst = img / Scalar(2, 2, 2);//这样除法操作之后会发现图片暗一些
	//dst = img * Scalar(2, 2, 2);//这样的操作是错误的,会报错,原因是不同类型的数据不能混合运算

	//以下来演示乘法运算该如何操作
	//1.创建和原本src相同尺寸类型的画布
	Mat drawer = Mat::zeros(img.size(), img.type());
	//2.用Scalar设置画布的初始灰度值
	drawer = Scalar(2, 2, 2);
	//3.用multiply()进行运算
	//语法说明(要乘的图像,要乘的图像,输出图像承载)
	multiply(drawer, img, dst);

	//test
	imshow("src", img);
	imshow("dst", dst);
}

通过这个例子我们可以知道,Scalar实际上是一种算子,可以对每一个像素点进行运算,运算值是灰度值.
运算用法编写的demo

void QuickDemo::operator_demo(Mat& img)
{
	//演示画布任意操作
	Mat dst;
	dst = img + Scalar(50, 50, 50);//这样加法的操作之后会发现图片会亮一些 
	dst = img - Scalar(50, 50, 50);//这样减法的操作之后会发现图片会亮一些 
	dst = img / Scalar(2, 2, 2);//这样除法操作之后会发现图片暗一些
	dst = img * Scalar(2, 2, 2);//这样的操作是错误的,会报错,原因是不同类型的数据不能混合运算

	//下面通过逐个像素点的相加的算法来表现加法
	//1.定义常用参量
	
	int n = img.rows;
	int m = img.cols;
	int dims = img.channels();
	//2.判断并进行逐点的操作
	Mat drawer = Mat::zeros(img.size(),img.type());
	drawer = Scalar(50, 50, 50);
	Mat dst = drawer.clone();
	if (dims == 1)//单通道
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				//这一点要特别注意,相加有可能会超过255,所以这边为了避免这种情况,要做一个防溢出
				dst.at<uchar>(i, j) = saturate_cast<uchar>(drawer.at<uchar>(i,j)+img.at<uchar>(i,j));
			}
		}
	}
	if (dims == 3)//三通道
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				Vec3b p1 = img.at<Vec3b>(i, j);
				Vec3b p2 = drawer.at<Vec3b>(i, j);
				dst.at<Vec3b>(i, j) = saturate_cast<uchar>(p1[0] + p2[0]);
				dst.at<Vec3b>(i, j) = saturate_cast<uchar>(p1[1] + p2[1]);
				dst.at<Vec3b>(i, j) = saturate_cast<uchar>(p1[2] + p2[2]);
			}
		}
	}

	Mat dst;
	//下面介绍api的用法
	//以下来演示乘法运算该如何操作
	//1.创建和原本src相同尺寸类型的画布
	Mat drawer = Mat::zeros(img.size(), img.type());
	//2.用Scalar设置画布的初始灰度值
	drawer = Scalar(2, 2, 2);
	//3.用multiply()进行运算
	//语法说明(要乘的图像,要乘的图像,输出图像承载)
	multiply(drawer, img, dst);
	cv::add(img, drawer, dst);
	//add的用法是(要加的图像,要加的图像,输出图像)
	
	cv::subtract(img, drawer, dst);
	
	cv::divide(img, drawer, dst);
	
	cv::multiply(img, drawer, dst);
	//test
	imshow("src", img);
	imshow("dst", dst);
}

滚动条演示调节亮度等参数(OpencvGUI)

demo01初体验

Mat src, dst, m;
int lightness = 50;

static void on_track(int , void *)//void意为任意类型的函数均可
{
	m = Scalar(lightness, lightness, lightness);
	//再调用api调节亮度
	cv::add(src, m, dst);
	//实时显示窗口
	imshow("亮度调节", dst);
}

void QuickDemo::track_bar_demo(Mat& img)
{
	//1.创建一个窗口
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	//2.调整上下值的限度
	int maxval = 100; //分别为所调整的最大亮度和初始亮度
	src = img.clone();
	m = Mat::zeros(img.size(), img.type());
	dst = Mat::zeros(img.size(), img.type());
	//3.创建滑动条
	//语法说明:("char(trackerbar的名字)","char(窗口的名称)","(int)需要改变的value","所能达到的最大值","(function)引起改变之后所回调的函数","(void)任意外带参数")
	createTrackbar("value_bar", "亮度调整", &lightness,maxval,on_track);
	on_track(50, 0);
}

这里对回调函数需要解释一下,意思是当产生了一个事件之后,系统捕获到了这个事件,就会把参数传回到callback函数中去。
总结来说:实现这个功能,首先需要一个窗口来承载trackerbar,然后设定好画布算子,然后编写回调函数,把传回来的参数利用起来即可。

优化版本,传递变量

static void on_track(int modify_value, void* userdata)//void意为任意类型的函数均可
{
	Mat img = *(Mat*) userdata;//将传建进来的img数据强转为Mat类型
	Mat m = Mat::zeros(img.size(), img.type());
	Mat src = img.clone();
	Mat dst;
	m = Scalar(modify_value, modify_value, modify_value);
	//再调用api调节亮度 
	cv::add(src , m, dst);
	//实时显示窗口
	imshow("亮度调整", dst);
}

void QuickDemo::track_bar_demo(Mat& img)
{
	//1.创建一个窗口
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	//2.调整上下值的限度
	int maxval = 100; //分别为所调整的最大亮度和初始亮度
	int lightness = 50;
	//3.创建滑动条
	//语法说明:("char(trackerbar的名字)","char(窗口的名称)","(int)需要改变的value","所能达到的最大值","(function)引起改变之后所回调的函数","(void)任意外带参数")
	createTrackbar("value_bar", "亮度调整", &lightness,maxval,on_track,(void*)(&img));
	on_track(50, &img);
}

如果需要同时调节亮度和对比度的话,就需要同时使用两个trackbar,同时合成两幅图像,要用addweight这个api

static void on_light(int modify_value, void* userdata)//万能指针 void意为任意类型的函数均可
{
	Mat img = *((Mat*) userdata);//将传建进来的img数据强转为Mat类型
	Mat m = Mat::zeros(img.size(), img.type());
	Mat src = img.clone();
	Mat dst= Mat::zeros(img.size(), img.type());
	//再调用api调节亮度 
	//此处是一个图像融合操作 调用cv::addWeighted()函数接口
	//dst=src1*alpha+src2*beta+gamma
	addWeighted(src, 1.0, m, 0.0, modify_value, dst);
	//实时显示窗口
	imshow("亮度与对比度调整", dst);
}

static void on_contract(int modify_value, void* userdata)//万能指针 void意为任意类型的函数均可
{
	Mat img = *((Mat*)userdata);//将传建进来的img数据强转为Mat类型
	Mat m = Mat::zeros(img.size(), img.type());
	Mat src = img.clone();
	Mat dst= Mat::zeros(img.size(), img.type());
	//此处是一个图像融合操作 调用cv::addWeighted()函数接口
	//为了精确地使用对比度,采用以下的方法
	//dst=src1*alpha+src2*beta+gamma
	double contract_val = modify_value / 100.0;
	addWeighted(src, contract_val, m, 0.0,0,dst);
	//实时显示窗口
	imshow("亮度与对比度调整", dst);
}

void QuickDemo::track_bar_demo(Mat& img)
{
	//1.创建一个窗口
	namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE);
	//2.调整上下值的限度
	int maxval_light = 100,lightness=50; //分别为所调整的最大亮度和初始亮度
	int maxval_contract =200, contractness = 120;//分别为最大的对比度和初始对比度
	//3.创建滑动条
	//语法说明:("char(trackerbar的名字)","char(窗口的名称)","(int)需要改变的value","所能达到的最大值","(function)引起改变之后所回调的函数","(void)任意外带参数")
	createTrackbar("light_bar", "亮度与对比度调整", &lightness, maxval_light,on_light,(void*)(&img));//这个回调函数用来解决亮度的问题
	createTrackbar("contract_bar", "亮度与对比度调整", &contractness, maxval_contract, on_contract, (void*)(&img));//这个回调函数用来解决对比度的问题
	on_light(50, &img);
}

总结一下滚动条,其实就是为不同的滚动条的数据提供不同的方法,如果是多种参数共同调节的话就要使用addWeight来实现。
重点是要学到addWeight这个函数的用法:改变亮度,我们通过改变加的gamma来改变Mat数组内每一个点的灰度值
改变对比度,那就是通过alpha的值来改变,改变比值,从而产生对比的这一种效果。

简单键盘操作的应用

void QuickDemo::key_demo(Mat& img)
{
	//本demo用于演示用键盘来操作图像
	char c;
	Mat dst = Mat::zeros(img.size(), img.type());
	while (1)
	{
		c = waitKey(100);
		if (c == 27)
		{
			break;
		}
		else if (c == '1')
		{
			cvtColor(img, dst, COLOR_BGR2HSV);
		}
		else if (c == '2')
		{
			cvtColor(img, dst, COLOR_BGR2GRAY);
		}
		imshow("dst", dst);
	}
}

三行代码,让opencv给我创建了十九个颜色表(

applyColorMap

void QuickDemo::color_style_demo(Mat& img)
{
	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,//index:0-11
	};
	Mat dst;
	int index = 0;
	while (1)
	{
		char c;
		c = waitKey(200);
		if (c == 27)
		{
			break;
		}
		applyColorMap(img, dst, colormap[(index%11)]);
		index++;
		imshow("dst", dst);
	}
}

图像像素的逻辑操作(位操作)

基本是就是对图像中的每一个像素点的灰度值进行和与或异或操作。

void QuickDemo::bitwises_demo(Mat& img)
{
	//首先演示的是一个填充矩形的算法
	//讲解如何使用opencv的函数进行绘制矩形
	Mat drawer1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat drawer2 = Mat::zeros(Size(256, 256), CV_8UC3);

	//调用api进行矩形的绘制
	//api参数:(被画的图像,要画的矩形的规格Rect(左上角的x坐标,左上角的y坐标,row,col),矩形的颜色是什么Scalar(255,255,0),绘制的线的宽度,如果是小于0的时候就代表不画线,填充该区域,产生锯齿时的办法(LINE_8,LINE_4,LINE_AA(反锯齿等)),)
	rectangle(drawer1, Rect(100, 100, 100, 100), Scalar(255, 255, 0), -1, LINE_8,0);
	rectangle(drawer2, Rect(150, 150, 80, 80), Scalar(0, 255,255), -1, LINE_8,0);
	imshow("drawer1", drawer1);
	imshow("drawer2", drawer2);
	Mat dst;
	bitwise_and(drawer1,drawer2,dst);
	//api参数:(输入图像,输入图像,输出图像)
	bitwise_or(drawer1, drawer2, dst);

	bitwise_not(drawer1, dst);
	//test-api
	imshow("dst", dst);
}

以上是关于Opencv视觉处理(C++)语法学习图像的算术与逻辑运算的主要内容,如果未能解决你的问题,请参考以下文章

EmguCV学习 与opencv的区别和联系

OpenCV中图像算术操作与逻辑操作

EmguCV学习 与opencv的区别和联系

机器视觉行业实践技巧 -- OpenCV技巧与方法:代码脚手架 -- 图像处理

机器视觉行业实践技巧 -- OpenCV技巧与方法:代码脚手架 -- 图像处理

何为计算机视觉?计算机视觉与数字图像处理的区别Opencv的起源。