Menu目录

OpenCV的canny图像背景透明化

作者:Carl Zhang | 更新时间:2017-07-02 | 分类:科技

毕业设计的时候做的项目是OpenCV图像处理,所以现在对图像处理产生了浓厚的兴趣,于是准备自己做个小项目。

软件:Visual Studio 2017,OpenCV v2.4.13。语言:C++。

这个项目有一步需要将两幅图片贴合,上层的图片需要经过边缘检测,然后去掉背景色,只保留边缘线条。举个例子,比如本站的logo:

初始logo

需要的结果:(网格在这里表示背景是透明的,一般用过PS的同学都懂。)

logo

但是网上基本上搜不到如何解决,于是我自己想了一个方法,代码如下,解释在后面:

// 代码片作者:Carl Zhang,转载请注明。 

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv/cv.h"
#include "opencv/highgui.h"

int main()
{
uchar r, g, b;
// 获取灰度图像。
cv::Mat image = ("image.jpg", 0);
cv::Mat image_canny;

// 二值化图像。
cv::threshold(image, image, threshold_low, threshold_high, CV_THRESH_OTSU);

// 获取图像边缘。
cv::Canny(image, image_canny, lowThreshold, lowThreshold*ratio, kernel_size);

// 反色。
cv::Mat newBImg(image_canny.rows, image_canny.cols, image_canny.type());
uchar* newBImgData = newBImg.data;
uchar* binaryData = image_canny.data;
int step = image_canny.step / sizeof(uchar);

for (int i = 0; i<image_canny.rows; i++)
for (int j = 0; j<image_canny.cols; j++)
newBImgData[i*step + j] = 255 - binaryData[i*step + j];

image_canny = newBImg.clone();

// 把canny图像从灰度转为BGRA 4通道图像。
cv::cvtColor(image_canny, image_canny, CV_GRAY2BGRA);

for (int i = 0; i < image_canny.rows; i++)
for (int j = 0; j < image_canny.cols; j++)
{
// R
r = image_canny.at<cv::Vec4b>(i, j)[2];
// G
g = image_canny.at<cv::Vec4b>(i, j)[1];
// B
b = image_canny.at<cv::Vec4b>(i, j)[0];

if (r > 200 && b > 200 && g > 200)
{
// A
image_canny.at<cv::Vec4b>(i, j)[3] = 0;
}
}

cv::imshow("alpha", image_canny);
cv::imwrite("alpha.png", image_canny);

cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}

其中反色的代码借鉴于:opencv二值图反色处理 - Bery的专栏 - 博客频道 - CSDN.NET。目的是为了把二值化以后的边缘检测结果图,白色变黑色,黑色变白色,因为我只要边缘的线条就可以了。

挑几行语句来分析一下:

1.

cv::Canny(image, image_canny, lowThreshold, lowThreshold*ratio, kernel_size);
这句代码是获取图像的边缘,具体请查看:Canny 边缘检测 — OpenCV 2.3.2 documentation

2.

cv::cvtColor(image_canny, image_canny, CV_GRAY2BGRA);
这句代码用于把原先的单通道图像转换为带alpha通道的四通道图像。

3.

// 代码片作者:Carl Zhang,转载请注明。 

for (int i = 0; i < image_canny.rows; i++)
for (int j = 0; j < image_canny.cols; j++)
{
r = image_canny.at<cv::Vec4b>(i, j)[2];
g = image_canny.at<cv::Vec4b>(i, j)[1];
b = image_canny.at<cv::Vec4b>(i, j)[0];

if (r > 200 && b > 200 && g > 200)
image_canny.at<cv::Vec4b>(i, j)[3] = 0;
}

这个循环相当于一个遍历,检测图片中所有的像素点。虽然说这个图变成了三通道,但实际上还是黑白图像,因此,每个像素点的三个通道的数值还是只有0或者255两种可能,所以设置一个阙值,如果该点r, g, b三个数值均大于200,则这个点认定为白色,把这个点的alpha值设置为0,即该点透明。整个循环结束以后,所有的白色点就变成了透明色。

最终效果图:(利用 cv::imwrite 函数生成的png图像)

logo

(本文为作者原创。转载请注明:转自carlzhang.xyz





*昵称:

*邮箱:

*留言: