C++ OpenCV實現(xiàn)灰度圖蒙版GrayMask的示例代碼
需求說明
在對圖像進行處理時,經(jīng)常會有這類需求:想對感興趣區(qū)域進行掩膜處理,只操作掩膜內(nèi)數(shù)據(jù),此時需要搭配掩膜繪制功能,并在繪制過程中希望能區(qū)分掩膜區(qū)和非掩膜區(qū);除了掩膜本身的線條以外,還希望掩膜內(nèi)圖像是原色,掩膜外圖像的顏色進行一定調(diào)整;通??梢圆捎脠D像透明化或者色彩單通道加深的方式實現(xiàn)。
比如對三通道的圖像,可以將掩膜外數(shù)據(jù)的紅通道數(shù)值提高,此時該部分圖像就會偏紅色,如下圖1所示。
圖1 顏色加深的蒙版效果
但是針對灰度圖,因為圖像數(shù)據(jù)本身就是單通道的,就不能借用顏色通道或者透明通道了;有一個基礎(chǔ)的辦法是將非掩膜區(qū)數(shù)據(jù)同時加減某個數(shù)值,這種方法簡單但有一個弊端,比如我加了50,那原圖200-255之間的數(shù)值都將變?yōu)?55,這樣就損壞了原圖的某些特征信息。為此,我們采用非線性的算法將其進行較為合理的數(shù)值調(diào)整。
下面介紹具體實現(xiàn)流程。
具體流程
1)構(gòu)造非線性參數(shù)。其中n為函數(shù)輸入的參數(shù),范圍在-100到100;a、b、k為算法參數(shù),公式見下。
n = min(max(n, -100), 100); int k = 4; float b = n / 100.f / k; float a = 1.0f + k * b;
2)參照上式,對掩膜外數(shù)據(jù)進行如下處理。
float temp = pow(float(in[j]) / 255.f, 1.0f / a) * (1.0 / (1 + b));
3)temp的數(shù)值需要進行校準,因為灰度值如果是uchar型,范圍在0-255之間,校準后乘上255,即可得到算法計算的結(jié)果。
if (temp > 1.0f) temp = 1.0f; if (temp < 0.0f) temp = 0.0f; uchar utemp = uchar(255 * temp); r[j] = utemp;
4)掩膜內(nèi)數(shù)值保持不變。
r[j] = in[j];
5)輸出圖像,完成。
功能函數(shù)
// 灰度圖蒙版 cv::Mat GrayMask(cv::Mat input, cv::Mat mask, int n) { // 通道判斷 if (input.channels() != 1) { return input; } // 非線性參數(shù) // 當n=100時,非掩膜區(qū)呈灰色;當n=0時,非掩膜區(qū)無變化;當n=-100時,非掩膜區(qū)黑色 // n越小,非掩膜區(qū)越暗,n越大,非掩膜區(qū)越灰 // 目的是區(qū)分非掩膜區(qū)和掩膜區(qū) n = min(max(n, -100), 100); int k = 4; float b = n / 100.f / k; float a = 1.0f + k * b; // 蒙版處理 cv::Mat result = cv::Mat::zeros(input.size(), input.type()); for (int i = 0; i < input.rows; ++i) { uchar *m = mask.ptr<uchar>(i); uchar *in = input.ptr<uchar>(i); uchar *r = result.ptr<uchar>(i); for (int j = 0; j < input.cols; ++j) { if (m[j] == 0) { float temp = pow(float(in[j]) / 255.f, 1.0f / a) * (1.0 / (1 + b)); if (temp > 1.0f) temp = 1.0f; if (temp < 0.0f) temp = 0.0f; uchar utemp = uchar(255 * temp); r[j] = utemp; } else { r[j] = in[j]; } } } return result; }
C++測試代碼
#include <iostream> #include <unordered_map> #include <unordered_set> #include <stdio.h> #include <io.h> #include <chrono> #include <time.h> #include <stdio.h> #include <direct.h> #include <ctime> #include <opencv2/core/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> using namespace std; using namespace cv; cv::Mat GrayMask(cv::Mat input, cv::Mat mask, int n); int main() { // 讀取灰度圖 cv::Mat src = imread("1.png",0); // 繪制掩膜 cv::Mat mask = cv::Mat::zeros(src.size(), CV_8UC1); cv::circle(mask, cv::Point(src.cols / 2, src.rows / 2), 100, cv::Scalar(255), -1); // 灰度圖蒙版 cv::Mat result = GrayMask(src, mask, 100); // 結(jié)果顯示 imshow("src", src); imshow("result", result); waitKey(0); system("pause"); return 0; } // 灰度圖蒙版 cv::Mat GrayMask(cv::Mat input, cv::Mat mask, int n) { // 通道判斷 if (input.channels() != 1) { return input; } // 非線性參數(shù) // 當n=100時,非掩膜區(qū)呈灰色;當n=0時,非掩膜區(qū)無變化;當n=-100時,非掩膜區(qū)黑色 // n越小,非掩膜區(qū)越暗,n越大,非掩膜區(qū)越灰 // 目的是區(qū)分非掩膜區(qū)和掩膜區(qū) n = min(max(n, -100), 100); int k = 4; float b = n / 100.f / k; float a = 1.0f + k * b; // 蒙版處理 cv::Mat result = cv::Mat::zeros(input.size(), input.type()); for (int i = 0; i < input.rows; ++i) { uchar *m = mask.ptr<uchar>(i); uchar *in = input.ptr<uchar>(i); uchar *r = result.ptr<uchar>(i); for (int j = 0; j < input.cols; ++j) { if (m[j] == 0) { float temp = pow(float(in[j]) / 255.f, 1.0f / a) * (1.0 / (1 + b)); if (temp > 1.0f) temp = 1.0f; if (temp < 0.0f) temp = 0.0f; uchar utemp = uchar(255 * temp); r[j] = utemp; } else { r[j] = in[j]; } } } return result; }
測試效果
圖2 原圖
圖3 灰度圖蒙版效果
如果函數(shù)有什么可以改進完善的地方,非常歡迎大家指出,一同進步何樂而不為呢~
到此這篇關(guān)于C++ OpenCV實現(xiàn)灰度圖蒙版GrayMask的示例代碼的文章就介紹到這了,更多相關(guān)C++ OpenCV灰度圖蒙版內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!