九、圖像處理基礎運算 OpenCV探索之路(十三):詳解掩膜mask

 一、圖像的代數運算與應用

0、經常使用的常數矩陣及類型說明

  爲了後續說明圖像與常數運算,這裏先講解下經常使用的基礎矩陣。首先看一個示例,其說明了如何構建三個指定大小的經常使用矩陣,全0陣,全1陣和對角陣。html

這裏須要說明的使,Size裏能夠爲src.cols和src.rows來標定圖像。其中CV_8UC1指8位無符號單通道,經常使用類型有:ios

CV_8UC1// 8位無符號單通道
CV_8UC3// 8位無符號3通道
CV_8UC4
CV_32FC1// 32位浮點型單通道
CV_32FC3// 32位浮點型3通道
CV_32FC4數組

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat mz = Mat::zeros(Size(5, 5), CV_8UC1); // 全零矩陣
	Mat mo = Mat::ones(Size(5, 5), CV_8UC1); // 全1矩陣
	Mat me = Mat::eye(Size(5, 5), CV_32FC1); // 對角線爲1的對角矩陣
	cout << "mz = " << endl << mz << endl << endl;
	cout << "mo = " << endl << mo << endl << endl;
	cout << "me = " << endl << me << endl << endl;
}

運行結果以下:ide

 

一、圖像相加

  上節已經講到,圖像是矩陣形式存在於內存中的,圖像與圖像相加意味着矩陣的相加,兩個矩陣對應元素相加,故圖像大小與類型必須保持一致;圖像與常數像加,是爲圖像矩陣中的每一個元素與該常數相加。函數

示例:須要注意兩幅圖片尺寸不一樣,須要用resize將尺寸轉換爲一致。同時,OpenCV基於圖像相加還提供了一種圖像線性混合疊加的方法addWeighted。post

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat img1 = imread("peppers.png");
	Mat img2 = imread("pears.png");
	Mat  mo= Mat::ones(Size(img2.cols,img2.rows), CV_8UC3);//RGB圖因此是3通道整型
	Mat dst, dst1,dst2;//存儲結果
	imshow("img1", img1);
	imshow("img2", img2);
	resize(img1, img1, Size(img2.cols, img2.rows));//調整圖片大小,使其與圖2大小一致
	//dst = img1 + img2;//這兩個加法效果相同
	add(img1, img2, dst);//注意:這兩個加法要求被加的圖片尺寸必須一致
     //dst1=img1+100; add(img1, 100*mo, dst1);//圖1+100 addWeighted(img1, 0.5, img2, 0.5, 0, dst2);//按權重相加,下一行dst輸出參數爲正常參數的一半; imshow("dst", dst); imshow("dst1", dst1); imshow("dst2", dst2); waitKey(0); }

原圖及效果圖以下所示:學習

 

 從圖中能夠看出圖1+常數後,圖像總體變亮,圖1與圖2相加後,總體亮度變大,疊加效果明顯。字體

二、圖像相減

  與圖像相加原理同樣,圖像相減即爲兩幅圖像對應位置的像素做差,若差值小於0,則該位置像素默認爲0.ui

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat img1 = imread("peppers.png");
	Mat img2 = imread("pears.png");
	Mat  mo= Mat::ones(Size(img2.cols,img2.rows), CV_8UC3);//RGB圖因此是3通道整型
	Mat dst, dst1,dst2;//存儲結果
	imshow("img1", img1);
	imshow("img2", img2);
	resize(img1, img1, Size(img2.cols, img2.rows));//調整圖片大小,使其與圖2大小一致
	//dst = img1 - img2;//這兩個加法效果相同
	subtract(img1, img2, dst);//注意:這兩個加法要求被加的圖片尺寸必須一致
//dst1=img1-100; subtract(img1, 100*mo, dst1);//圖1+100 addWeighted(img1, 0.5, img2, -0.5, 0, dst2);//按權重相減,下一行dst輸出參數爲正常參數的一半; imshow("dst", dst); imshow("dst1", dst1); imshow("dst2", dst2); waitKey(0); }

  運行結果以下:url

 

 

能夠看出減去一個常數值後總體亮度減少,而兩圖相減後,總體變暗,相減效果明顯。

能夠看出,圖像加減能夠調節圖像亮度。

三、圖像相乘

  圖像相乘,原理同矩陣相加,相同大小的圖像矩陣對應元素乘積做爲新的像素值。

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat img1 = imread("rice.png");
	Mat img2 = imread("saturn.png");
	Mat  mo= Mat::ones(Size(img2.cols,img2.rows), CV_8UC1);//灰圖因此是1通道整型
	Mat dst, dst1,dst2;//存儲結果
	cvtColor(img1, img1, CV_RGB2GRAY);//雖然是灰度圖,可是是按RGB方法讀入的,因此還須要轉換下格式爲灰度圖
	imshow("img1", img1);
	cvtColor(img2, img2, CV_RGB2GRAY);
	imshow("img2", img2);
	resize(img1, img1, Size(img2.cols, img2.rows));//調整圖片大小,使其與圖2大小一致
	//dst = img1 * 2;//這兩個乘法效果相同
	multiply(img1, 2*mo, dst1);
	multiply(img1, img2, dst1);//注意:這兩個加法要求被加的圖片尺寸必須一致
	imshow("dst", dst);
    imshow("dst1", dst1);
	
	waitKey(0);
}

  原圖及效果以下:

 

結果能夠按出,圖1與圖2灰度值較高的區域相乘後,像素米線獲得提高。由於圖1周邊部分像素值低,且乘值小,故乘積後結果依然很小,結果呈現黑色。

四、圖像相除

同理,對兩幅圖像進行圖像相除

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat img1 = imread("rice.png");
	Mat img2 = imread("saturn.png");
	Mat  mo= Mat::ones(Size(img2.cols,img2.rows), CV_8UC1);//灰圖因此是1通道整型
	Mat dst, dst1,dst2;//存儲結果
	cvtColor(img1, img1, CV_RGB2GRAY);//雖然是灰度圖,可是是按RGB方法讀入的,因此還須要轉換下格式爲灰度圖
	imshow("img1", img1);
	cvtColor(img2, img2, CV_RGB2GRAY);
	imshow("img2", img2);
	resize(img1, img1, Size(img2.cols, img2.rows));//調整圖片大小,使其與圖2大小一致
	//dst = img1/2;//這兩個乘法效果相同
	divide(img1, 2*mo, dst);
	divide(img1, img2, dst1);//注意:這兩個加法要求被加的圖片尺寸必須一致
	imshow("dst", dst);
        imshow("dst1", dst1);
	
	waitKey(0);
}

  結果以下:

 

 能夠看出,圖像乘除能夠調節圖像對比度。

 前面只對加減乘除進行了標識,有時候咱們還會須要用到一些其餘的操做,這裏將經常使用的運算操做列舉出來以下所示:

void add(InputArray src1, InputArray src2, OutputArray dst,InputArray mask=noArray(), int dtype=-1);//dst = src1 + src2
void subtract(InputArray src1, InputArray src2, OutputArray dst,InputArray mask=noArray(), int dtype=-1);//dst = src1 - src2
void multiply(InputArray src1, InputArray src2,OutputArray dst, double scale=1, int dtype=-1);//dst = scale*src1*src2
void divide(InputArray src1, InputArray src2, OutputArray dst,double scale=1, int dtype=-1);//dst = scale*src1/src2
void divide(double scale, InputArray src2,OutputArray dst, int dtype=-1);//dst = scale/src2
void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst);//dst = alpha*src1 + src2
void addWeighted(InputArray src1, double alpha, InputArray src2,double beta, double gamma, OutputArray dst, int dtype=-1);//dst = alpha*src1 + beta*src2 + gamma
void sqrt(InputArray src, OutputArray dst);//計算每一個矩陣元素的平方根
void pow(InputArray src, double power, OutputArray dst);//src的power次冪
void exp(InputArray src, OutputArray dst);//dst = e**src(**表示指數的意思)
void log(InputArray src, OutputArray dst);//dst = log(abs(src))

  

二、圖像的邏輯運算

0、經常使用的圖形說明

   opencv提供了不少繪圖函數,這些函數基本上包含了咱們須要用到的經常使用圖形,能夠供咱們在實際應用中進行圖像的截取,目標的標註等。下面是一些包含經常使用圖形的示例:

#include "stdafx.h"
#include <stdio.h>
#include <vector>
#include <cv.h>
#include <highgui.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	//建立一張白色大小爲800x800的圖片,全部繪圖多在這圖上實現
	Mat matSrc(800, 800, CV_8UC3, Scalar(255, 255, 255));
	Mat matClone = matSrc.clone();

	//畫普通直線
	line(matSrc, Point(100, 50), Point(600, 50), Scalar(0, 0, 255), 1, LINE_8, 0);

	//畫帶箭頭直線
	arrowedLine(matSrc, Point(100, 100), Point(600, 100), Scalar(0, 0, 255), 1, LINE_8, 0, 0.1);

	//畫矩形
	rectangle(matSrc, Rect(100, 150, 500, 50), Scalar(0, 255, 0), 1, LINE_8, 0);

	//畫圓
	circle(matSrc, Point(300, 300), 100, Scalar(0, 255, 0), 1, LINE_8, 0);

	//畫橢圓
	ellipse(matSrc, Point(400, 400), Size(100, 60), -45, 0, 360, Scalar(0, 255, 0), 1, LINE_8, 0);

	//填充多邊形
	Point pts[5];
	pts[0] = Point(500, 500);
	pts[1] = Point(700, 500);
	pts[2] = Point(750, 750);
	pts[3] = Point(450, 750);
	pts[4] = Point(500, 500);
	fillConvexPoly(matSrc, pts, 5, Scalar(0, 255, 0), LINE_8, 0);

	//畫輪廓點
	vector<vector<Point> > vContours;
	vector<Vec4i> hierarchy;
	Mat matGray;
	cvtColor(matSrc, matGray, CV_BGR2GRAY);
	Mat matBinary(matSrc.rows, matSrc.cols, CV_8UC1);
	threshold(matGray, matBinary, 200, 255, THRESH_BINARY);
	findContours(matBinary, vContours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point(0, 0));
	drawContours(matClone, vContours, -1, Scalar(255, 0, 255));

	//顯示文字
	putText(matSrc, string("opencv is open source"), Point(50, 650), 0, 1, Scalar(0, 128, 255), 1);

	//顯示圖像
	namedWindow("draw");
	namedWindow("Contours");
	imshow("draw", matSrc);
	imshow("Contours", matClone);
	cvWaitKey();

	return 0;
}

 程序運行結果以下:

總結以下:

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);//直線
void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int line_type = 8, int shift = 0, double tipLength = 0.1);//帶箭頭的直線
void rectangle(CV_IN_OUT Mat& img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);//矩形
void circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);//圓
void ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle,const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);//橢圓
void fillConvexPoly(Mat& img, const Point* pts, int npts, const Scalar& color, int lineType = LINE_8, int shift = 0);//填充多邊形
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());//畫輪廓點
void putText(Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = 8, bool bottomLeftOrigin = false);//顯示字體

  詳細參數說明請看opencv基礎(5)——畫圖操做line()/arrowedLine()/rectangle()/circle()/fillConvexPoly()/drawContours()/putText()

一、經常使用的邏輯運算說明

  圖像的邏輯運算即爲圖像矩陣之間的邏輯運算,包含圖像之間的邏輯與,邏輯或邏輯非,邏輯異或等操做。圖像的邏輯運算是針對二值圖像進行的,由於只有二值圖像的像素才具備邏輯0和1。

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

    下面是一個相關示例:

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
	Mat img1 = imread("circles.png");
	Mat img2 = imread("coins.png");
	Mat binary1, binary2;//存儲結果
	cvtColor(img1, img1, CV_RGB2GRAY);//雖然是灰度圖,可是是按RGB方法讀入的,因此還須要轉換下格式爲灰度圖
	imshow("img1", img1);
	cvtColor(img2, img2, CV_RGB2GRAY);
	imshow("img2", img2);
	resize(img1, img1, Size(img2.cols, img2.rows));//調整圖片大小,使其與圖2大小一致
	//dst = img1 * 2;//這兩個乘法效果相同
	threshold(img1, binary1, 66, 255, THRESH_BINARY_INV);//全局二值化
	threshold(img2, binary2, 80, 255, THRESH_BINARY_INV);//全局二值化

	Mat yu,huo,fei,yi_huo;
	bitwise_and(binary1, binary2, yu);
	bitwise_or(binary1, binary2, huo);
	bitwise_not(binary1, fei);
	bitwise_xor(binary1, binary2, yi_huo);


	imshow("binary1", binary1);
    imshow("binary2", binary2);
	imshow("yu", yu);//與的結果
	imshow("huo", huo);//與的結果
	imshow("fei", fei);//與的結果
	imshow("yi_huo", yi_huo);//與的結果
	waitKey(0);
}

 原圖及先相關邏輯運算的結果以下所示:

 

二、經常使用的邏輯運算應用——Mask掩膜

數字圖像處理中的掩膜的概念是借鑑於PCB製版的過程,在半導體制造中,許多芯片工藝步驟採用光刻技術,用於這些步驟的圖形「底片」稱爲掩膜(也稱做「掩模」),其做用是:在硅片上選定的區域中對一個不透明的圖形模板遮蓋,繼而下面的腐蝕或擴散將隻影響選定的區域之外的區域。
圖像掩膜與其相似,用選定的圖像、圖形或物體,對處理的圖像(所有或局部)進行遮擋,來控制圖像處理的區域或處理過程。
數字圖像處理中,掩模爲二維矩陣數組,有時也用多值圖像,圖像掩模主要用於:
①提取感興趣區,用預先製做的感興趣區掩模與待處理圖像相乘,獲得感興趣區圖像,感興趣區內圖像值保持不變,而區外圖像值都爲0。
②屏蔽做用,用掩模對圖像上某些區域做屏蔽,使其不參加處理或不參加處理參數的計算,或僅對屏蔽區做處理或統計。
③結構特徵提取,用類似性變量或圖像匹配方法檢測和提取圖像中與掩模類似的結構特徵。
④特殊形狀圖像的製做。
  值得注意的是,在全部圖像基本運算的操做函數中,凡是帶有掩膜(mask)的處理函數,其掩膜都參與運算(輸入圖像運算完以後再與掩膜圖像或矩陣運算)。

   下面是一個掩膜提取相關區域的運算示例:

#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

int main()
{
	Mat image, mask;
	Rect r1(100, 100, 250, 300);
	Mat img1, img2, img3, img4;
	image = imread("111.jpg");
	mask = Mat::zeros(image.size(), CV_8UC1);
	mask(r1).setTo(255);
	img1 = image(r1);
	image.copyTo(img2, mask);

	image.copyTo(img3);
	img3.setTo(0, mask);


	imshow("Image sequence", image);
	imshow("img1", img1);
	imshow("img2", img2);
	imshow("img3", img3);
	imshow("mask", mask);

	waitKey();
	return 0;
}

  原圖及運行結果以下:

    

能夠看出,掩膜mask對原圖進行了一個指定區域的截取,應用這個方法能夠來提取機器視覺中感興趣的部分。其運算原理以下

 

 

參考資料:

OpenCV學習筆記:resize函數改變圖像的大小

【OpenCV學習筆記】之圖像混合、疊加和對比度、亮度調整

opencv基礎(5)——畫圖操做line()/arrowedLine()/rectangle()/circle()/fillConvexPoly()/drawContours()/putText()

OpenCV探索之路(十三):詳解掩膜mask

相關文章
相關標籤/搜索