一、圖像疊加
關門放代碼
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src1, src2, dst;
src1 = imread("C:\\Users\\Administrator\\Desktop\\test.jpg");
src2 = imread("C:\\Users\\Administrator\\Desktop\\test2.jpg");
if (!src1.data) {
cout << "could not load image Linux Logo..." << endl;
return -1;
}
if (!src2.data) {
cout << "could not load image WIN7 Logo..." << endl;
return -1;
}
double alpha = 0.5;
if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type()) {
addWeighted(src1, alpha, src2, (1.0 - alpha), 0.0, dst);//將src2設置透明度1.0-alpha後疊加在src1上。
// multiply(src1, src2, dst, 1.0);
imshow("linuxlogo", src1);
imshow("win7logo", src2);
namedWindow("blend demo", CV_WINDOW_AUTOSIZE);
imshow("blend demo", dst);
}
else {
printf("could not blend images , the size of images is not same...\n");
return -1;
}
waitKey(0);
return 0;
}
以上代碼中主要的幾個知識點解釋下:
這裏要求兩個圖像的長寬需要一樣。
1.if (!src1.data) {}
這裏用於判斷圖片是否加載成功,如果加載失敗則停止運行。
2.addWeighted(src1, alpha, src2, (1.0 - alpha), 0.0, dst);
公式:
其中α的取值範圍爲0~1之間
參數1:輸入圖像src1
參數2:輸入圖像src1的alpha值
參數3:輸入圖像src2
參數4:輸入圖像src2的alpha值
參數5:gamma值
參數6:輸出混合圖像
這句代碼的意思爲:將src2設置透明度1.0-alpha後疊加在src1上存於dst。
看效果
二、調整圖像亮度與對比度
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("C:\\Users\\Administrator\\Desktop\\test.png");
//src2 = imread("C:\\Users\\Administrator\\Desktop\\test1.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char input_win[] = "input image";
//cvtColor(src, src, CV_BGR2GRAY);
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
// contrast and brigthtness changes
int height = src.rows;
int width = src.cols;
dst = Mat::zeros(src.size(), src.type());//創建一個空白的圖像
float alpha = 1.2;
float beta = 30;
Mat m1;
src.convertTo(m1, CV_32F);//默認是CV_8UC轉換到CV32F
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (src.channels() == 3) {
float b = m1.at<Vec3f>(row, col)[0];// blue
float g = m1.at<Vec3f>(row, col)[1]; // green
float r = m1.at<Vec3f>(row, col)[2]; // red
// output
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);
}
else if (src.channels() == 1) {
float v = src.at<uchar>(row, col);
dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
}
}
}
char output_title[] = "contrast and brightness change demo";
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(output_title, dst);
waitKey(0);
return 0;
}
以上代碼中主要的幾個知識點解釋下:
1.dst = Mat::zeros(src.size(), src.type());//返回指定大小和類型的零數組。即創建一個空的圖像。
2.src.convertTo(m1, CV_32F);
默認Mat是CV_8UC的Vec3b。
這句的意思是把CV_8UC轉換到CV32F的Vec3f。
Vec3b對應三通道的順序是blue、green、red的uchar類型數據。
Vec3f對應三通道的float類型數據,要比Vec3b更精確。
3.三通道dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
公式:
Mat.at<Vec3b>(y,x)[index]=value 給每個像素點每個通道賦值,x與y是像素點。index是通道,rgb通道就是對應012。如果沒有賦值則是取值。
4.單通道dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
與第3點類似,單通道的寫法。
5.alpha=1.2;
alpha大於1則更亮,若小於1則偏暗。
如下圖,調整後是不是亮瞎了。
三、繪製形狀與文字
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat bgImage;
const char* drawdemo_win = "draw shapes and text demo";
void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
void MyPolygon();
void MyText();
void RandomLineDemo();
int main(int argc, char** argv) {
bgImage = imread("C:\\Users\\Administrator\\Desktop\\test.png");
if (!bgImage.data) {
printf("could not load image...\n");
return -1;
}
MyLines();
MyRectangle();
MyEllipse();
MyCircle();
MyPolygon();
MyText();
namedWindow("random line demo", CV_WINDOW_AUTOSIZE);
imshow("random line demo", bgImage);
RandomLineDemo();
waitKey(0);
return 0;
}
/*
畫一條線條
*/
void MyLines() {
Point p1 = Point(20, 30);
Point p2;
p2.x = 400;
p2.y = 400;
Scalar color = Scalar(0, 0, 255);
line(bgImage, p1, p2, color, 1, LINE_AA);
}
/*
畫一個方形框框
*/
void MyRectangle() {
Rect rect = Rect(200, 100, 300, 300);
Scalar color = Scalar(255, 0, 0);
rectangle(bgImage, rect, color, 2, LINE_8);
}
/*
畫一個橢圓框框
*/
void MyEllipse() {
Scalar color = Scalar(0, 255, 0);
ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 0, 0, 360, color, 2, LINE_8);
}
/*
畫一個圓形框框
*/
void MyCircle() {
Scalar color = Scalar(0, 255, 255);
Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
circle(bgImage, center, 150, color, 2, 8);
}
/*
畫一個實心方形
*/
void MyPolygon() {
Point pts[1][5];
pts[0][0] = Point(100, 100);
pts[0][1] = Point(100, 200);
pts[0][2] = Point(200, 200);
pts[0][3] = Point(200, 100);
pts[0][4] = Point(100, 100);
const Point* ppts[] = { pts[0] };
int npt[] = { 5 };
Scalar color = Scalar(255, 12, 255);
fillPoly(bgImage, ppts, npt, 1, color, 8);
}
/*
畫一段文字
*/
void MyText() {
putText(bgImage, "Hello OpenCV", Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(12, 23, 200), 3, 8);
}
//隨機畫線段
void RandomLineDemo() {
RNG rng(12345);
Point pt1;
Point pt2;
for (int i = 0; i < 100000; i++) {
pt1.x = rng.uniform(0, bgImage.cols);
pt2.x = rng.uniform(0, bgImage.cols);
pt1.y = rng.uniform(0, bgImage.rows);
pt2.y = rng.uniform(0, bgImage.rows);
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
if (waitKey(50) > 0) {
break;
}
line(bgImage, pt1, pt2, color, 1, 8);
imshow("random line demo", bgImage);
}
}
以上代碼中主要的幾個知識點解釋下:
該段代碼中如果分辨不清畫的圖與對應的代碼,可以分別註釋某一些代碼,一段一段運行。
1.line(bgImage, p1, p2, color, 1, LINE_AA);
畫一條線,bgImage是要繪畫的目的圖像。p1是Point起點。p2是Point終點。color是Scalar類型顏色。1是代表粗細。LINE_AA是線的類型,(LINE_4\LINE_8\LINE_AA),LINE_4與LINE_8都有鋸齒,LINE_AA沒有鋸齒。
2.rectangle(bgImage, rect, color, 2, LINE_8);
畫一個方形框框,bgImage是要繪畫的目的圖像。rect是Rect類型對象,rect內包括起點xy與終點xy。color是Scalar類型顏色。2代表粗細,LINE_8代表有鋸齒的類型。
3.ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 0, 0, 360, color, 2, LINE_8);
畫一個橢圓框框。首先我們理解一下橢圓【橢圓是平面內到定點F1、F2的距離之和等於常數(大於|F1F2|)的動點P的軌跡,F1、F2稱爲橢圓的兩個焦點。其數學表達式爲:|PF1|+|PF2|=2a(2a>|F1F2|)。橢圓有一個長半軸,就是原點到最遠的頂點的距離。一個短半軸,原點到最近的頂點的距離】。
bgImage是要繪畫的目的圖像。Point(bgImage.cols / 2, bgImage.rows / 2)代表原點即是中心點的位置。Size(bgImage.cols / 4, bgImage.rows / 8)左邊的數是長半軸,右邊是短半軸。第一個0是旋轉角度。第二個0是起點角度。360是終點角度。color是Scalar類型顏色。2代表粗細,LINE_8代表有鋸齒的類型。
4.circle(bgImage, center, 150, color, 2, 8);
畫一個圓形。center代表原點即是中心點的位置。150是半徑。color是Scalar類型顏色。2代表粗細,LINE_8代表有鋸齒的類型。8其實就是LINE_8,可以在Visual Studio裏按住Ctrl+鼠標點擊LINE_8,就會跳轉到LINE_8的定義。
5.fillPoly(bgImage, ppts, npt, 1, color, 8);
畫一個實心方形。bgImage是要繪畫的目的圖像。ppts是一個二維數組。npt是多邊形頂點數目。1是多邊形數量。color是Scalar類型顏色。8代表有鋸齒的類型。
6.rng.uniform(0, bgImage.cols);
產生一個0到bgImage.cols之間的整型隨機數。
7.waitKey(50)
waitKey()與waitKey(0)都是無限等待。
waitKey(50)是等待50毫秒,繼續運行。
來看看效果