专栏首页行走的机械人图像腌膜Mask的常规操作你真的信手拈来吗?

图像腌膜Mask的常规操作你真的信手拈来吗?

我对图像腌膜的含义一直有些模糊,今天写了几行代码,证明了我这模糊的印象倒是正确的。今天借一个给图片添加水印的小例子,给大家总结一些图像腌膜的常规操作。

首先先了解一下图像腌膜的定义:。。。

额,找了一圈好像并没有啥特别正式的官方定义/我记得曾在书上看到过来着~

其实腌膜可以抽象为一个黑白相间的图,或者膜,黑色的像素值为0,白色为1。将这个膜和你原本的图像重合到一起,黑色区域被忽略,仅剩下白色区域,就是这样。

就像把白色区域的图像抠出来一样,”抠图“就是腌膜Mask最常干的事。

废话少说,咱们开始咱们的小实践吧。

一:普通加水印:图像加和

先看一下今天要处理的水印图,一张白底红字的logo图:

然后再看一下我们的底图:

我们要吧logo,也就是水印加到左上角去,首先我们想到的就是在左上角掏个和logo图片一样大小的ROI区域出来,然后直接将logo添加到ROI区域里,来看代码:

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
  Mat srcImage, logoImage, dstImage;
  srcImage = imread("1.jpg");//读取底图
  logoImage = imread("logo1.jpg");//读入logo图片
  //【1】ROI区域与原图直接混合
  Mat imgROI = srcImage(Rect(20, 20, logoImage.cols, logoImage.rows));  //Rect方法定义ROI,注意宽是:cols;高是rows。
  logoImage.copyTo(imgROI);//将logo图片拷贝到img的ROI上(注意copyTo函数要求两图像大小和类型都相同,否则无效)
  imshow("混合后", srcImage);
  waitKey(0);
  return 0;
}

运行效果如下:

可以看到白色的底并不是我们想要的,所以就需要用到腌膜的相关抠图,将五个红色的字”抠“出来。

二:抠图操作加水印

首先我们要完成的操作就是将这五个字识别出来,也就是抠出来,对于我们这个logo自然很简单啦,只需要转灰度,然后阈值化操作一下就可以了:

1,我们先定义一个腌膜Mask,然后将logo图像转为灰度图像存入到Mask中:

  Mat mask;//定义腌膜
  cvtColor(logoImage, mask, COLOR_BGR2GRAY);//将logo转成灰度图

处理后得到如下灰度图:

2,对腌膜Mask这个图像矩阵进行取反操作:

bitwise_not(mask, mask);//对mask图像取反,白色(255)变成黑色(0)

对于上面操作我们需要多加解释一下。

图像的基本运算有很多种,比如两幅图像可以相加相减、相乘、相除、位运算、平方根、对数、绝对值等;

图像也可以放大、缩小、旋转,还可以截取其中的一部分作为ROI(感兴趣区域)进行操作,各个颜色通道还可以分别提取及对各个颜色通道进行各种运算操作。

所以我们自然可以对图像进行与,或,非,异或等操作啦。

 //bitwise_and、bitwise_or、bitwise_xor、bitwise_not这四个按位操作函数。
void bitwise_and(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 & src2
void bitwise_or(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 | src2
void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());//dst = src1 ^ src2
void bitwise_not(InputArray src, OutputArray dst,InputArray mask=noArray());//dst = ~src
  • bitwise_and:对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作,1&1=1,1&0=0,0&1=0,0&0=0
  • bitwise_or:对图像(灰度图像或彩色图像均可)每个像素值进行二进制“或”操作,1|1=1,1|0=1,0|1=1,0|0=0
  • bitwise_xor:对图像(灰度图像或彩色图像均可)每个像素值进行二进制“异或”操作,1^1=0,1^0=1,0^1=1,0^0=0
  • bitwise_not:对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作,~1=0,~0=1
引用自:https://blog.csdn.net/u011028345/article/details/77278467

为什么要对我们处理后得灰度图进行取反操作呢?因为我们开头说过,在腌膜中黑色无效,白色有效,而我们得灰度图的底色确实白色的,字确实黑色的,所以进行取反操作,结果如下:

3,对取反后的图进行阈值化操作,抠出五个字:

threshold(mask, mask, 100, 255, THRESH_BINARY);//对mask进行二值化,将mask进一步处理

得到如下图所示:

4,进行图像融合

通过上面步骤,我们得到了如上图所示的黑底白字的腌膜了,下面就把腌膜加入到图像融合中去。

 Mat imgROI = srcImage(Rect(20, 20, logoImage.cols, logoImage.rows));
 logoImage.copyTo(imgROI, mask); //将logo拷贝到imgROI上,掩码为不为0的部分起作用,为0的部分不起作用

可以看到copyTo方法中,有第二个参数mask,我们只需要传给他就可以了,很多现成的函数接口都有图像腌膜这个参数,现在你知道怎么用了吧。

来看看效果图:

是不是变成水印了呢?

三:添加非矩形的Mask区域

我们选取ROI区域一般都是用矩形,所以圈出来的区域都是矩形的,如何添加非矩形的呢?

首先我们读取我们的logo图片,为了观察方便我们换了如下一个logo:

Mat logo2Image = imread("logo2.jpg");//读取logo2

需要强调的是,接下来我们的操作都是基于这张logo的大小来进行的:

1,在原图开出logo大小的ROI区域:

Mat imgROI = srcImage(Rect(20, 20, logo2Image.cols, logo2Image.rows));

2,创建一个同logo一样大的纯黑的腌膜mask:

Mat mask = Mat::zeros(logo2Image.size(), CV_8UC1);

3,在黑色腌膜上画出一个白色内填充的圆:

circle(mask, Point(mask.rows / 2, mask.cols / 2), 120, Scalar(255), -1, 8);

4,最后就还是一样的操作,将logo复制到原图ROI区域中去,并申明腌膜:

logo2Image.copyTo(imgROI, mask);//将logo拷贝到imgROI上,掩码为不为0的部分起作用,为0的部分不起作用

运行效果如下图:

虽然有些丑,但好看又不能拿来找对象,所以就这样叭。

到此,会添加圆形了,其他非规则的形状就要通过关键点来进行确定了,我们只需要将上述步骤中的第三步:在黑色腌膜上画圆变成画不规则多边形就行了,如下:

 vector<vector<Point>> contour;
  vector<Point> pts;
  pts.push_back(Point(30, 45));
  pts.push_back(Point(100, 15));
  pts.push_back(Point(300, 145));
  pts.push_back(Point(330, 240));
  pts.push_back(Point(50, 250));
  contour.push_back(pts);
  drawContours(mask, contour, 0, Scalar::all(255), -1);

创建多个点,然后进行轮廓绘制就好了,drawContours这个函数最后传的参数-1为线宽,当为正时为宽度,为负则为向内填充,和画圆函数类似。

THE END

本文分享自微信公众号 - Opencv视觉实践(gh_31e12b1be0e0),作者:是周旋哎

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【opencv实践】图像增强基本操作

    上面这幅黑乎乎的图就是我们今天要处理的图片,这是书的一页,但特别特别黑,对于这种因为阴影而导致的细节缺失,我们就可以尝试对其进行图像增强了。

    周旋
  • 【工程材料B】一:材料力学性能概述

    我们可以看到,材料的性能分为材料的使用性能和材料的工艺性能。使用性能是指材料在使用过程中所表现的性能, 包括力学性能、 物理性能、化学性能。工艺性能是指材料在加...

    周旋
  • 【opencv实践】easy卡尔曼滤波上:浅谈

    距离上一篇文到现在有十天左右了,现在我又来更新啦!现在正值我们专业课程多的一个学期,还赶上疫情在家学习效率低,所以没能有精力写推文了,不过幸好大家都还在,我会一...

    周旋
  • 学HTTP协议所要知道的基础知识(微总结)

    skylark
  • 【机器学习圈子里的裙带关系】学术“朋友圈”罪与罚

    来源:Reddit 作者:闻菲 【新智元导读】或许你以为搞学术做研究可以不受世俗干扰,殊不知有人在的地方就有江湖。在学术圈,跟对人或许跟做好事情一样重要...

    新智元
  • 量化交易系统开发软件架构设计

    量化交易是用模型去刻画盈利逻辑,通过模型来做风险控制;量化交易还可以避免心理干扰,

    源中瑞科技ruiecjo
  • arguments,想说爱你不容易

    HTML5学堂-码匠:arguments是关于函数参数的一个知识点,也是很多企业面试时的“必考点”,arguments和形参有何不同?如何去检测实参或形参的长度...

    HTML5学堂
  • 使用Xposed强制androidwebView开启debug模式

    从 https://developer.chrome.com/devtools/docs/remote-debugging 我们可以知道在android 4.4...

    IMWeb前端团队
  • 使用Xposed强制android WebView开启debug模式使用Xposed强制android WebView开启debug模式Xposed前期工作

    从 https://developer.chrome.com/devtools/docs/remote-debugging 我们可以知道在android 4.4...

    一个会写诗的程序员
  • app令牌的一个token实现

    app登陆验证不能使用session来判断了。然后查资料都说用令牌,没找到合适的方法,我的眼界太小。另外,越来越感觉基础的重要,比如,session是什么,我竟...

    Ryan-Miao

扫码关注云+社区

领取腾讯云代金券