C++之OpenCV圖像高光調(diào)整具體流程
實(shí)現(xiàn)原理
PS中的高光命令是一種校正由于太接近相機(jī)閃光燈而有些發(fā)白的焦點(diǎn)的方法。在用其他方式采光的圖像中,這種調(diào)整也可用于使高光區(qū)域變暗。要實(shí)現(xiàn)圖像的高光調(diào)整,首先要識別出高光區(qū);再通過對高光區(qū)的色彩進(jìn)行一定變換,使其達(dá)到提光或者暗化效果;最后也是最重要的,就是對高光區(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ū)。因?yàn)槲覀円R別高光,所以thresh通過gray*gray,得到的圖像中原本亮的地方則為亮,取平均值當(dāng)閾值,進(jìn)行二值化得到掩膜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ū)邊緣進(jìn)行平滑過渡。假設(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,進(jìn)行高光區(qū)提亮。對非高光區(qū)而言,midrate都為1,brightrate都為0,即沒有變化;對高光區(qū)而言,midrate都為1.5,brightrate都為0.125,所以色彩數(shù)值均有所增加,帶來了提亮效果;對邊緣地區(qū),midrate和brightrate起到了很好的過渡作用。
注意:temp要進(jìn)行數(shù)值限制,假設(shè)temp大于1,則進(jìn)行uchar處理后數(shù)值會因?yàn)轭愋驮虍a(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為正值時(shí),高光區(qū)有明顯提亮效果;反之,則變更暗。
如果函數(shù)有什么可以改進(jìn)完善的地方,非常歡迎大家指出,一同進(jìn)步何樂而不為呢~
到此這篇關(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-06C++實(shí)現(xiàn)LeetCode(77.Combinations 組合項(xiàng))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(Combinations 組合項(xiàng)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07VisualStudio?制作Dynamic?Link?Library動態(tài)鏈接庫文件的詳細(xì)過程
這篇文章主要介紹了VisualStudio?制作Dynamic?Link?Library動態(tài)鏈接庫文件的詳細(xì)過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08C語言可變參數(shù)與函數(shù)參數(shù)的內(nèi)存對齊詳解
這篇文章主要為大家詳細(xì)介紹了C語言可變參數(shù)與函數(shù)參數(shù)的內(nèi)存對齊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03wchar_t,char,string,wstring之間的相互轉(zhuǎn)換
以下是對wchar_t,char,string,wstring之間的相互轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-09-09