C++ OpenCV实现灰度图蒙版GrayMask的示例代码
需求说明
在对图像进行处理时,经常会有这类需求:想对感兴趣区域进行掩膜处理,只操作掩膜内数据,此时需要搭配掩膜绘制功能,并在绘制过程中希望能区分掩膜区和非掩膜区;除了掩膜本身的线条以外,还希望掩膜内图像是原色,掩膜外图像的颜色进行一定调整;通常可以采用图像透明化或者色彩单通道加深的方式实现。
比如对三通道的图像,可以将掩膜外数据的红通道数值提高,此时该部分图像就会偏红色,如下图1所示。
图1 颜色加深的蒙版效果
但是针对灰度图,因为图像数据本身就是单通道的,就不能借用颜色通道或者透明通道了;有一个基础的办法是将非掩膜区数据同时加减某个数值,这种方法简单但有一个弊端,比如我加了50,那原图200-255之间的数值都将变为255,这样就损坏了原图的某些特征信息。为此,我们采用非线性的算法将其进行较为合理的数值调整。
下面介绍具体实现流程。
具体流程
1)构造非线性参数。其中n为函数输入的参数,范围在-100到100;a、b、k为算法参数,公式见下。
n = min(max(n, -100), 100); int k = 4; float b = n / 100.f / k; float a = 1.0f + k * b;
2)参照上式,对掩膜外数据进行如下处理。
float temp = pow(float(in[j]) / 255.f, 1.0f / a) * (1.0 / (1 + b));
3)temp的数值需要进行校准,因为灰度值如果是uchar型,范围在0-255之间,校准后乘上255,即可得到算法计算的结果。
if (temp > 1.0f) temp = 1.0f; if (temp < 0.0f) temp = 0.0f; uchar utemp = uchar(255 * temp); r[j] = utemp;
4)掩膜内数值保持不变。
r[j] = in[j];
5)输出图像,完成。
功能函数
// 灰度图蒙版 cv::Mat GrayMask(cv::Mat input, cv::Mat mask, int n) { // 通道判断 if (input.channels() != 1) { return input; } // 非线性参数 // 当n=100时,非掩膜区呈灰色;当n=0时,非掩膜区无变化;当n=-100时,非掩膜区黑色 // n越小,非掩膜区越暗,n越大,非掩膜区越灰 // 目的是区分非掩膜区和掩膜区 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); // 结果显示 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; } // 非线性参数 // 当n=100时,非掩膜区呈灰色;当n=0时,非掩膜区无变化;当n=-100时,非掩膜区黑色 // n越小,非掩膜区越暗,n越大,非掩膜区越灰 // 目的是区分非掩膜区和掩膜区 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 灰度图蒙版效果
如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~
上一篇:C语言详细讲解注释符号的使用
栏 目:C代码
下一篇:C语言实现折半查找法(二分法)
本文标题:C++ OpenCV实现灰度图蒙版GrayMask的示例代码
本文地址:http://www.codeinn.net/misctech/215328.html