C++之OpenCV图像高光调整具体流程

实现原理

PS中的高光命令是一种校正由于太接近相机闪光灯而有些发白的焦点的方法。在用其他方式采光的图像中,这种调整也可用于使高光区域变暗。要实现图像的高光调整,首先要识别出高光区;再通过对高光区的色彩进行一定变换,使其达到提光或者暗化效果;最后也是最重要的,就是对高光区和非高光区的边缘作平滑处理。

下方介绍具体流程。

具体流程

1)读取识别图像的原图,并转灰度图,再归一化。

// 生成灰度图
cv::Mat gray = cv::Mat::zeros(input.size(), CV_32FC1);
cv::Mat f = input.clone();
f.convertTo(f, CV_32FC3);
vector<cv::Mat> pics;
split(f, pics);
gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
gray = gray / 255.f;

图1 灰度图

2)确定高光区。因为我们要识别高光,所以thresh通过gray*gray,得到的图像中原本亮的地方则为亮,取平均值当阈值,进行二值化得到掩膜mask。

// 确定高光区
cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
thresh = gray.mul(gray);
// 取平均值作为阈值
Scalar t = mean(thresh);
cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
mask.setTo(255, thresh >= t[0]);

图2 掩膜图

3)对掩膜区边缘进行平滑过渡。假设light为50,那么midrate的掩膜区值为1.5,黑色区为1,过渡区为1~1.5;bright的掩膜区为0.125,黑色区为0,过渡区为0~0.125。

// 参数设置
int max = 4;
float bright = light / 100.0f / max;
float mid = 1.0f + max * bright;

// 边缘平滑过渡
cv::Mat midrate = cv::Mat::zeros(input.size(), CV_32FC1);
cv::Mat brightrate = cv::Mat::zeros(input.size(), CV_32FC1);
for (int i = 0; i < input.rows; ++i)
{
	uchar *m = mask.ptr<uchar>(i);
	float *th = thresh.ptr<float>(i);
	float *mi = midrate.ptr<float>(i);
	float *br = brightrate.ptr<float>(i);
	for (int j = 0; j < input.cols; ++j)
	{
		if (m[j] == 255)
		{
			mi[j] = mid;
			br[j] = bright;
		}
		else {
			mi[j] = (mid - 1.0f) / t[0] * th[j] + 1.0f;
			br[j] = (1.0f / t[0] * th[j])*bright;
		}
	}
}

4)根据midrate和brightrate,进行高光区提亮。对非高光区而言,midrate都为1,brightrate都为0,即没有变化;对高光区而言,midrate都为1.5,brightrate都为0.125,所以色彩数值均有所增加,带来了提亮效果;对边缘地区,midrate和brightrate起到了很好的过渡作用。

注意:temp要进行数值限制,假设temp大于1,则进行uchar处理后数值会因为类型原因产生突变,那么图像也就变成了五颜六色。

// 高光提亮,获取结果图
cv::Mat result = cv::Mat::zeros(input.size(), input.type());
for (int i = 0; i < input.rows; ++i)
{
	float *mi = midrate.ptr<float>(i);
	float *br = brightrate.ptr<float>(i);
	uchar *in = input.ptr<uchar>(i);
	uchar *r = result.ptr<uchar>(i);
	for (int j = 0; j < input.cols; ++j)
	{
		for (int k = 0; k < 3; ++k)
		{
			float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
			if (temp > 1.0f)
				temp = 1.0f;
			if (temp < 0.0f)
				temp = 0.0f;
			uchar utemp = uchar(255*temp);
			r[3 * j + k] = utemp;
		}
	}
}

C++测试代码

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

using namespace std;
using namespace cv;

cv::Mat HighLight(cv::Mat input, int light);

int main()
{
	cv::Mat src = imread("test3.jpg");
	int light1 = 50;
	int light2 = -50;
	cv::Mat result1 = HighLight(src, light1);
	cv::Mat result2 = HighLight(src, light2);
	imshow("original", src);
	imshow("result1", result1);
	imshow("result2", result2);
	waitKey(0);
	return 0;
}

// 图像高光选取
cv::Mat HighLight(cv::Mat input, int light)
{
	// 生成灰度图
	cv::Mat gray = cv::Mat::zeros(input.size(), CV_32FC1);
	cv::Mat f = input.clone();
	f.convertTo(f, CV_32FC3);
	vector<cv::Mat> pics;
	split(f, pics);
	gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
	gray = gray / 255.f;

	// 确定高光区
	cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
	thresh = gray.mul(gray);
	// 取平均值作为阈值
	Scalar t = mean(thresh);
	cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
	mask.setTo(255, thresh >= t[0]);

	// 参数设置
	int max = 4;
	float bright = light / 100.0f / max;
	float mid = 1.0f + max * bright;

	// 边缘平滑过渡
	cv::Mat midrate = cv::Mat::zeros(input.size(), CV_32FC1);
	cv::Mat brightrate = cv::Mat::zeros(input.size(), CV_32FC1);
	for (int i = 0; i < input.rows; ++i)
	{
		uchar *m = mask.ptr<uchar>(i);
		float *th = thresh.ptr<float>(i);
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		for (int j = 0; j < input.cols; ++j)
		{
			if (m[j] == 255)
			{
				mi[j] = mid;
				br[j] = bright;
			}
			else {
				mi[j] = (mid - 1.0f) / t[0] * th[j] + 1.0f;
				br[j] = (1.0f / t[0] * th[j])*bright;
			}
		}
	}

	// 高光提亮,获取结果图
	cv::Mat result = cv::Mat::zeros(input.size(), input.type());
	for (int i = 0; i < input.rows; ++i)
	{
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		uchar *in = input.ptr<uchar>(i);
		uchar *r = result.ptr<uchar>(i);
		for (int j = 0; j < input.cols; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
				if (temp > 1.0f)
					temp = 1.0f;
				if (temp < 0.0f)
					temp = 0.0f;
				uchar utemp = uchar(255*temp);
				r[3 * j + k] = utemp;
			}

		}
	}
	return result;
}

测试效果

图1 原图

图2 light为50的效果图

图3 light为-50的效果图

从测试效果中可以看出,高光区随light变化而产生亮度变化,当light为正值时,高光区有明显提亮效果;反之,则变更暗。

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

到此这篇关于OpenCV图像高光调整的文章就介绍到这了,更多相关OpenCV图像高光调整内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中实现OpenCV图像分割与分水岭算法

    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征. API介绍 void watershed( InputArray image, InputOutputArray markers ); 参数说明: image: 必须是一个8bit 3通道彩色图像矩阵序列 markers: 在执行分水岭函数watershed之前,必须对第二个参数markers

  • OpenCV和C++实现图像的翻转(镜像)、平移、旋转、仿射与透视变换

    目录 一.翻转(镜像) 二.仿射扭曲 获取变换矩阵 仿射扭曲函数 warpAffine 旋转 平移 三.仿射变换 四.透视变换 综合示例 总结 官网教程 一.翻转(镜像) 头文件 quick_opencv.h:声明类与公共函数 #pragma once #include <opencv2\opencv.hpp> using namespace cv; class QuickDemo { public: ... void flip_Demo(Mat& image); void rotat

  • opencv3/C++图像滤波实现方式

    图像滤波在opencv中可以有多种实现形式 自定义滤波 如使用3×3的掩模: 对图像进行处理. 使用函数filter2D()实现 #include<opencv2/opencv.hpp> using namespace cv; int main() { //函数调用filter2D功能 Mat src,dst; src = imread("E:/image/image/daibola.jpg"); if(!src.data) { printf("can not l

  • opencv3/C++图像边缘提取方式

    canny算子实现 使用track bar 调整canny算子参数,提取到合适的图像边缘. #include<iostream> #include<opencv2/opencv.hpp> using namespace cv; void trackBar(int, void*); int s1=0,s2=0; Mat src, dst; int main() { src = imread("E:/image/image/daibola.jpg"); if(src

  • opencv3/C++ PHash算法图像检索详解

    PHash算法即感知哈希算法/Perceptual Hash algorithm,计算基于低频的均值哈希.对每张图像生成一个指纹字符串,通过对该字符串比较可以判断图像间的相似度. PHash算法原理 将图像转为灰度图,然后将图片大小调整为32*32像素并通过DCT变换,取左上角的8*8像素区域.然后计算这64个像素的灰度值的均值.将每个像素的灰度值与均值对比,大于均值记为1,小于均值记为0,得到64位哈希值. PHash算法实现 将图片转为灰度值 将图片尺寸缩小为32*32 resize(src

  • opencv3/C++图像像素操作详解

    RGB图像转灰度图 RGB图像转换为灰度图时通常使用: 进行转换,以下尝试通过其他对图像像素操作的方式将RGB图像转换为灰度图像. #include<opencv2/opencv.hpp> #include<math.h> using namespace cv; int main() { //像素操作 Mat src,dst; src = imread("E:/image/image/daibola.jpg"); if(src.empty()) { printf

  • 使用c++实现OpenCV图像横向&纵向拼接

    功能函数 // 图像拼接 cv::Mat ImageSplicing(vector<cv::Mat> images,int type) { if (type != 0 && type != 1) type = 0; int num = images.size(); int newrow = 0; int newcol = 0; cv::Mat result; // 横向拼接 if (type == 0) { int minrow = 10000; for (int i = 0;

  • C++之OpenCV图像高光调整具体流程

    实现原理 PS中的高光命令是一种校正由于太接近相机闪光灯而有些发白的焦点的方法.在用其他方式采光的图像中,这种调整也可用于使高光区域变暗.要实现图像的高光调整,首先要识别出高光区:再通过对高光区的色彩进行一定变换,使其达到提光或者暗化效果:最后也是最重要的,就是对高光区和非高光区的边缘作平滑处理. 下方介绍具体流程. 具体流程 1)读取识别图像的原图,并转灰度图,再归一化. // 生成灰度图 cv::Mat gray = cv::Mat::zeros(input.size(), CV_32FC1

  • OpenCV 图像对比度的实践

    本文主要介绍了OpenCV 图像对比度,具有一定的参考价值,感兴趣的可以了解一下 实现原理 图像对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,即指一幅图像灰度反差的大小.差异范围越大代表对比越大,差异范围越小代表对比越小.设置一个基准值thresh,当percent大于0时,需要令图像中的颜色对比更强烈,即数值距离thresh越远,则变化越大:当percent等于1时,对比强到极致,只有255和0的区分:当percent等于0时,不变:当percent小于0时,对比下降

  • python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)

    图像边框的实现 图像边框设计的主要函数 cv.copyMakeBorder()--实现边框填充 主要参数如下: 参数一:源图像--如:读取的img 参数二--参数五分别是:上下左右边的宽度--单位:像素 参数六:边框类型: cv.BORDER_CONSTANT--cv.BORDER_REPLICATE--cv.BORDER_REFLECT--cv.BORDER_WRAP--cv.BORDER_REFLECT_101--cv.BORDER_TRANSPARENT--cv.BORDER_REFLEC

  • OpenCV 图像旋转、平移、缩放操作代码

    目录 1 缩放图片 2 翻转图片 2.1 垂直翻转 2.2 水平翻转 2.3 水平垂直翻转 3 平移图片 本文是 OpenCV图像视觉入门之路的第7篇文章,本文详细的进行了图像的缩放 cv2.resize().旋转 cv2.flip().平移 cv2.warpAffine()等操作. 1 缩放图片 缩放就是调整图片的大小,使用cv2.resize()函数实现缩放,可以按照比例缩放,也可以按照指定的大小缩放:也可以指定缩放方法为线性插值INTER_LINEAR. 放过程中有五种插值方式: cv2.

  • C#图像对比度调整的方法

    本文实例讲述了C#图像对比度调整的方法.分享给大家供大家参考.具体如下: //定义对比度调整函数 private static Bitmap ContrastP(Bitmap a, double v) { System.Drawing.Imaging.BitmapData bmpData = a.LockBits(new Rectangle(0, 0, a.Width, a.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, Syst

  • C#图像透明度调整的方法

    本文实例讲述了C#图像透明度调整的方法.分享给大家供大家参考.具体如下: //定义图像透明度调整函数 public Bitmap PTransparentAdjust(Bitmap src,int num) { try { int w = src.Width; int h = src.Height; Bitmap dstBitmap = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bpp

  • Python实现PS图像明亮度调整效果示例

    本文实例讲述了Python实现PS图像明亮度调整效果.分享给大家供大家参考,具体如下: 这里用 Python 实现 PS 图像调整中的明度调整: 我们知道,一般的非线性RGB亮度调整只是在原有R.G.B值基础上增加和减少一定量来实现的,而PS的明度调整原理还得从前面那个公式上去找.我们将正向明度调整公式: RGB = RGB + (255 - RGB) * value / 255 转换为 RGB = (RGB * (255 - value) + 255 * value) / 255, 如果val

  • python opencv 图像尺寸变换方法

    利用Python OpenCV中的 cv.Resize(源,目标,变换方法)就可以实现变换为想要的尺寸了 源文件:就不用说了 目标:你可以对图像进行倍数的放大和缩小 也可以直接的输入尺寸大小 变换的方法: CV_INTER_NN - 最近邻插值, CV_INTER_LINEAR - 双线性插值 (缺省使用) CV_INTER_AREA - 使用象素关系重采样.当图像缩小时候,该方法可以避免波纹出现.当图像放大时,类似于 CV_INTER_NN 方法.. CV_INTER_CUBIC - 立方插值

  • opencv 图像腐蚀和图像膨胀的实现

    语言:python+opencv 为什么使用图像腐蚀和图像膨胀 如图,使用图像腐蚀进行去噪,但是为压缩噪声. 对腐蚀过的图像,进行膨胀处理,可以去除噪声,并保持原样形状. 图像腐蚀 腐蚀主要针对的是二值图像,如只有0和1两个值, 两个输入对象:1原始二值图像,2卷积核 使用卷积核遍历原始二值图像,如果卷积核对应的元素值均为1,其值才为1,否则为0.如图,红色为卷积核. 腐蚀后的结果示意图见下面,效果是将边缘抹掉一部分. 使用方法:erode 中文翻译:侵蚀 处理结果=cv2.erode(原始图像

  • opencv 图像礼帽和图像黑帽的实现

    python + OpenCV 图像礼帽 图像礼帽 也叫图像顶帽 礼帽图像=原始图像-开运算图像 得到噪声图像 开运算:先腐蚀再膨胀 使用对象:二值图像 使用方法:morphologyEx cv2.MORPH_TOPHAT 结果=cv2.morphologyEx(原始图像,cv2.MORPH_TOPHAT,卷积核) 卷积核示例:k=np.ones((10,10),np.uint8) import cv2 import numpy as np o=cv2.imread("tophat.bmp&qu

随机推荐