C++之OpenCV圖像高光調(diào)整具體流程
實現(xiàn)原理
PS中的高光命令是一種校正由于太接近相機閃光燈而有些發(fā)白的焦點的方法。在用其他方式采光的圖像中,這種調(diào)整也可用于使高光區(qū)域變暗。要實現(xiàn)圖像的高光調(diào)整,首先要識別出高光區(qū);再通過對高光區(qū)的色彩進行一定變換,使其達到提光或者暗化效果;最后也是最重要的,就是對高光區(qū)和非高光區(qū)的邊緣作平滑處理。
下方介紹具體流程。
具體流程
1)讀取識別圖像的原圖,并轉(zhuǎn)灰度圖,再歸一化。
// 生成灰度圖 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;

2)確定高光區(qū)。因為我們要識別高光,所以thresh通過gray*gray,得到的圖像中原本亮的地方則為亮,取平均值當(dāng)閾值,進行二值化得到掩膜mask。
// 確定高光區(qū) 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]);

3)對掩膜區(qū)邊緣進行平滑過渡。假設(shè)light為50,那么midrate的掩膜區(qū)值為1.5,黑色區(qū)為1,過渡區(qū)為1~1.5;bright的掩膜區(qū)為0.125,黑色區(qū)為0,過渡區(qū)為0~0.125。
// 參數(shù)設(shè)置
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)根據(jù)midrate和brightrate,進行高光區(qū)提亮。對非高光區(qū)而言,midrate都為1,brightrate都為0,即沒有變化;對高光區(qū)而言,midrate都為1.5,brightrate都為0.125,所以色彩數(shù)值均有所增加,帶來了提亮效果;對邊緣地區(qū),midrate和brightrate起到了很好的過渡作用。
注意:temp要進行數(shù)值限制,假設(shè)temp大于1,則進行uchar處理后數(shù)值會因為類型原因產(chǎn)生突變,那么圖像也就變成了五顏六色。
// 高光提亮,獲取結(jié)果圖
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;
// 確定高光區(qū)
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]);
// 參數(shù)設(shè)置
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;
}
}
}
// 高光提亮,獲取結(jié)果圖
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 原圖
從測試效果中可以看出,高光區(qū)隨light變化而產(chǎn)生亮度變化,當(dāng)light為正值時,高光區(qū)有明顯提亮效果;反之,則變更暗。
如果函數(shù)有什么可以改進完善的地方,非常歡迎大家指出,一同進步何樂而不為呢~
到此這篇關(guān)于OpenCV圖像高光調(diào)整的文章就介紹到這了,更多相關(guān)OpenCV圖像高光調(diào)整內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言文件操作中 fgets與fputs 函數(shù)詳解
這篇文章主要介紹了C語言文件操作中 fgets與fputs 函數(shù)詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06
C++實現(xiàn)LeetCode(77.Combinations 組合項)
這篇文章主要介紹了C++實現(xiàn)LeetCode(Combinations 組合項),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
VisualStudio?制作Dynamic?Link?Library動態(tài)鏈接庫文件的詳細過程
這篇文章主要介紹了VisualStudio?制作Dynamic?Link?Library動態(tài)鏈接庫文件的詳細過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
C語言可變參數(shù)與函數(shù)參數(shù)的內(nèi)存對齊詳解
這篇文章主要為大家詳細介紹了C語言可變參數(shù)與函數(shù)參數(shù)的內(nèi)存對齊,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
wchar_t,char,string,wstring之間的相互轉(zhuǎn)換
以下是對wchar_t,char,string,wstring之間的相互轉(zhuǎn)換進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-09-09

