资讯专栏INFORMATION COLUMN

OpenCV-基于自定义色条实现灰度图上色

ChristmasBoy / 1095人阅读

摘要:函数原理首先需要将灰度值图转化为的通道灰度图,运用归一化函数可以实现之后考虑到颜色和灰度的关系,比如最低的颜色为蓝色对应灰度值,最高的颜色为红色对应灰度值,只需要找出其变化的规律即可。

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

场景需求

       Qt在进行2D图像显示时,有很方便的色条接口,可以让灰度图基于其设计的色条进行上色,比如设置1为红色,0.55为黄色,0.45为绿色,0为蓝色,那么灰度图就会在归一化后按照从蓝到红(从小到大)进行渐变色上色。但是有时候这个接口需要搭配的代码太多,给开发带来一定麻烦,因此我基于其原理写了一个可以替代该功能的函数GrayToColor_ColorBar。

       函数原理:首先需要将灰度值图转化为0-255的8通道(uchar)灰度图,运用归一化函数可以实现;之后考虑到颜色和灰度的关系,比如最低的颜色为蓝色(0,0,255)对应灰度值0,最高的颜色为红色(255,0,0)对应灰度值255,只需要找出其变化的规律即可。

       下方为具体实现函数和测试代码。

功能函数代码

/** * @brief GrayToColor_ColorBar             运用色条灰度图上色(1:红色,param1:黄色,param2:绿色,0:蓝色) * @param phase                            输入的灰色图像,通道为1 * @param param1                           色条参数1 * @param param2                           色条参数2 * @return                                 上色后的图像 */cv::Mat GrayToColor_ColorBar(cv::Mat &phase, float param1, float param2){	CV_Assert(phase.channels() == 1);    // 色条参数1必须大于色条参数2	if (param2 >= param1)	{		return cv::Mat::zeros(10, 10, CV_8UC1);	}	cv::Mat temp, result, mask;	// 将灰度图重新归一化至0-255	cv::normalize(phase, temp, 255, 0, cv::NORM_MINMAX);	temp.convertTo(temp, CV_8UC1);	// 创建掩膜,目的是为了隔离nan值的干扰	mask = cv::Mat::zeros(phase.size(), CV_8UC1);	mask.setTo(255, phase == phase);	// 初始化三通道颜色图	cv::Mat color1, color2, color3;	color1 = cv::Mat::zeros(temp.size(), temp.type());	color2 = cv::Mat::zeros(temp.size(), temp.type());	color3 = cv::Mat::zeros(temp.size(), temp.type());	int row = phase.rows;	int col = phase.cols;	// 基于灰度图的灰度层级,给其上色,最底的灰度值0为蓝色(255,0,0),最高的灰度值255为红色(0,0,255),中间的灰度值127为绿色(0,255,0)	// 不要惊讶蓝色为什么是(255,0,0),因为OpenCV中是BGR而不是RGB	for (int i = 0; i < row; ++i)	{		uchar *c1 = color1.ptr(i);		uchar *c2 = color2.ptr(i);		uchar *c3 = color3.ptr(i);		uchar *r = temp.ptr(i);		uchar *m = mask.ptr(i);		for (int j = 0; j < col; ++j)		{			if (m[j] == 255)			{				if (r[j] > (param1 * 255) && r[j] <= 255)				{					c1[j] = 255;					c2[j] = uchar((1 / (1 - param1)) * (255 - r[j]));					c3[j] = 0;				}				else if (r[j] <= (param1 * 255) && r[j] > (param2 * 255))				{					c1[j] = uchar((1 / (param1 - param2)) * r[j] - (param2 / (param1 - param2)) * 255);					c2[j] = 255;					c3[j] = 0;				}				else if (r[j] <= (param2 * 255) && r[j] >= 0)				{					c1[j] = 0;					c2[j] = uchar((1 / param2) * r[j]);					c3[j] = uchar(255 - (1 / param2) * r[j]);				}				else {					c1[j] = 0;					c2[j] = 0;					c3[j] = 0;				}			}		}	}	// 三通道合并,得到颜色图	vector images;	images.push_back(color3);	images.push_back(color2);	images.push_back(color1);	cv::merge(images, result);	return result;}

C++测试代码

#include#include#includeusing namespace std;using namespace cv;void UnitPolar(int squaresize, cv::Mat& mag, cv::Mat& ang);void UnitCart(int squaresize, cv::Mat& x, cv::Mat& y);cv::Mat GrayToColor_ColorBar(cv::Mat &phase, float param1, float param2);int main(void){	cv::Mat mag, ang, result, result3;	UnitPolar(2001, mag, ang);	mag.at(10, 10) = nan("");	clock_t start, end;	start = clock();	result = GrayToColor_ColorBar(mag,0.5,0.3);	end = clock();	double diff = end - start;	cout << "time:" << diff / CLOCKS_PER_SEC << endl;	system("pause");	return 0;}void UnitPolar(int squaresize, cv::Mat& mag, cv::Mat& ang) {	cv::Mat x;	cv::Mat y;	UnitCart(squaresize, x, y);                //产生指定范围内的指定数量点数,相邻数据跨度相同	// OpenCV自带的转换有精度限制,导致结果有一定差异性	//cv::cartToPolar(x, y, mag, ang, false); //坐标转换	mag = cv::Mat(x.size(), x.type());	ang = cv::Mat(x.size(), x.type());	int row = mag.rows;	int col = mag.cols;	float *m, *a, *xx, *yy;	for (int i = 0; i < row; ++i)	{		m = mag.ptr(i);		a = ang.ptr(i);		xx = x.ptr(i);		yy = y.ptr(i);		for (int j = 0; j < col; ++j)		{			m[j] = sqrt(xx[j] * xx[j] + yy[j] * yy[j]);			a[j] = atan2(yy[j], xx[j]);		}	}}void UnitCart(int squaresize, cv::Mat& x, cv::Mat& y) {	CV_Assert(squaresize % 2 == 1);	x.create(squaresize, squaresize, CV_32FC1);	y.create(squaresize, squaresize, CV_32FC1);	//设置边界	x.col(0).setTo(-1.0);	x.col(squaresize - 1).setTo(1.0f);	y.row(0).setTo(1.0);	y.row(squaresize - 1).setTo(-1.0f);	float delta = 2.0f / (squaresize - 1.0f);  //两个元素的间隔	//计算其他位置的值	for (int i = 1; i < squaresize - 1; ++i) {		x.col(i) = -1.0f + i * delta;		y.row(i) = 1.0f - i * delta;	}}/** * @brief GrayToColor_ColorBar             运用色条灰度图上色(1:红色,param1:黄色,param2:绿色,0:蓝色) * @param phase                            输入的灰色图像,通道为1 * @param param1                           色条参数1 * @param param2                           色条参数2 * @return                                 上色后的图像 */cv::Mat GrayToColor_ColorBar(cv::Mat &phase, float param1, float param2){	CV_Assert(phase.channels() == 1);	// 色条参数1必须大于色条参数2	if (param2 >= param1)	{		return cv::Mat::zeros(10, 10, CV_8UC1);	}	cv::Mat temp, result, mask;	// 将灰度图重新归一化至0-255	cv::normalize(phase, temp, 255, 0, cv::NORM_MINMAX);	temp.convertTo(temp, CV_8UC1);	// 创建掩膜,目的是为了隔离nan值的干扰	mask = cv::Mat::zeros(phase.size(), CV_8UC1);	mask.setTo(255, phase == phase);	// 初始化三通道颜色图	cv::Mat color1, color2, color3;	color1 = cv::Mat::zeros(temp.size(), temp.type());	color2 = cv::Mat::zeros(temp.size(), temp.type());	color3 = cv::Mat::zeros(temp.size(), temp.type());	int row = phase.rows;	int col = phase.cols;	// 基于灰度图的灰度层级,给其上色,最底的灰度值0为蓝色(255,0,0),最高的灰度值255为红色(0,0,255),中间的灰度值127为绿色(0,255,0)	// 不要惊讶蓝色为什么是(255,0,0),因为OpenCV中是BGR而不是RGB	for (int i = 0; i < row; ++i)	{		uchar *c1 = color1.ptr(i);		uchar *c2 = color2.ptr(i);		uchar *c3 = color3.ptr(i);		uchar *r = temp.ptr(i);		uchar *m = mask.ptr(i);		for (int j = 0; j < col; ++j)		{			if (m[j] == 255)			{				if (r[j] > (param1 * 255) && r[j] <= 255)				{					c1[j] = 255;					c2[j] = uchar((1 / (1 - param1)) * (255 - r[j]));					c3[j] = 0;				}				else if (r[j] <= (param1 * 255) && r[j] > (param2 * 255))				{					c1[j] = uchar((1 / (param1 - param2)) * r[j] - (param2 / (param1 - param2)) * 255);					c2[j] = 255;					c3[j] = 0;				}				else if (r[j] <= (param2 * 255) && r[j] >= 0)				{					c1[j] = 0;					c2[j] = uchar((1 / param2) * r[j]);					c3[j] = uchar(255 - (1 / param2) * r[j]);				}				else {					c1[j] = 0;					c2[j] = 0;					c3[j] = 0;				}			}		}	}	// 三通道合并,得到颜色图	vector images;	images.push_back(color3);	images.push_back(color2);	images.push_back(color1);	cv::merge(images, result);	return result;}

测试效果

图1 灰度图
图2 效果图1
图3 效果图2

       如上图所示,为了方便,我生成了一个2001*2001的图像矩阵,图1为灰度图,图2图3是经过颜色处理后的颜色图,满足了前面提到的需求,这两个效果图对应的参数不一样。

       如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/124757.html

相关文章

  • 数字像处理:OpenCV-Python中的直方均衡知识介绍及函数equalizeHist详解

    摘要:对于图像整体比较暗的情况,直方图均衡能得到类似的效果。这些内容老猿在数字图像处理直方图均衡算法研究及模拟实现中进行介绍,本部分主要详细介绍提供的直方图均衡函数。更多图像直方图处理的内容请参考数字图像处理第三章学习总结感悟直方图处理的介绍。 ...

    ityouknow 评论0 收藏0
  • 2,一个人体姿态识别的项目实现

    摘要:函数如进行固定阈值分割,进行自适应阈值分割,它有个参数,如用来进行固定阈值分割。二值化跟阈值分割并不等同。用来实现阈值分割,是缩写,代表当前的阈值,暂时不用理会。 ...

    xiaowugui666 评论0 收藏0
  • 利用python进行识别相似片(一)

    摘要:图像指纹与汉明距离在介绍下面其他判别相似度的方法前,先补充一些概念。汉明距离为,即代表两张图片完全一样。下一次将讲述利用和以训练好的模型来进行人脸识别。本文参考文章和图片来源的文章赖勇浩的文章下一篇地址利用进行识别相似图片二 文章简介 在网上看到python做图像识别的相关文章后,真心感觉python的功能实在太强大,因此将这些文章总结一下,建立一下自己的知识体系。当然了,图像识别这个...

    HitenDev 评论0 收藏0
  • OpenCV 形态学操作应用——提取水平与垂直线

    摘要:通过使用两个最基本的形态学操作膨胀与腐蚀,使用不同的结构元素实现对输入图像的操作得到想要的结果。 文章目录 原理方法提取步骤输入图像彩色图像 `imread`转换...

    dackel 评论0 收藏0
  • 数字像处理:使用直方统计进行像增强

    摘要:如果将二者的处理的一些数据结合起来使用,则就是基于直方图统计进行图像增强。图中是通过直方图统计进行图像增强后的结果,可以看到另一个钨丝的比较明显的结构。 一、引...

    coolpail 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<