OpenCV探索之路(二):圖像處理的基礎知識點串燒


opencv圖像初始化操作

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
       //這些方式都是自己擁有獨立的內存空間
	Mat img1(2, 2, CV_8UC3, Scalar(0, 0, 255));
	cout << img1 << endl;

	int sz[3] = { 2,2,2 };
	Mat img2(3, sz, CV_8UC1, Scalar(0, 0, 0));
	//cout << img2 << endl;

	Mat img5;
	img5.create(4, 4, CV_8UC3);
	cout << img5 << endl;

	Mat img6 = Mat::zeros(4, 4, CV_8UC3);
	cout << img6 << endl;

	Mat img7 = img6.clone();
	cout << img7 << endl;

	Mat img8;
	img6.copyTo(img8);
	cout << img8 << endl;
	
	//下面都是淺拷貝,指針指向同一個實例
	Mat img9 = img8;
	Mat img10(img8);

	waitKey(0);
	return 0;
}

圖像二值化操作

兩種方法,全局固定閾值二值化和局部自適應閾值二值化

全局固定閾值很容易理解,就是對整幅圖像都是用一個統一的閾值來進行二值化;

局部自適應閾值則是根據像素的鄰域塊的像素值分布來確定該像素位置上的二值化閾值。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat image = imread("lol1.jpg", CV_LOAD_IMAGE_GRAYSCALE); //注意了,必須是載入灰度圖
	if (image.empty())
	{
		cout << "read image failure" << endl;
		return -1;
	}

	// 全局二值化
	int th = 100;
	Mat global;
	threshold(image, global, th, 255, CV_THRESH_BINARY_INV);

	// 局部二值化
	int blockSize = 25;
	int constValue = 10;
	Mat local;
	adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);

	imshow("全局二值化", global);
	imshow("局部二值化", local);

	waitKey(0);
	return 0;
}

原始圖

兩種二值化效果對比

腐蝕操作

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;
int main()
{
	Mat SrcPic = imread("lena.jpg");
	imshow("Src Pic", SrcPic);
	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); //getStructuringElement函數返回的是指定形狀和尺寸的結構元素
	Mat DstPic;
	erode(SrcPic, DstPic, element); //腐蝕操作
	imshow("腐蝕效果圖", DstPic);
	waitKey();
	return 0;
}


運行效果

使用 均值濾波實現圖像模糊

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;
int main()
{
	Mat SrcPic = imread("lena.jpg");
	imshow("Src Pic", SrcPic);
	Mat DstPic;
	blur(SrcPic, DstPic, Size(7, 7));
	imshow("均值模糊效果圖", DstPic);
	waitKey();
	return 0;
}


運行效果

canny邊緣檢測

思路:將原始圖像轉化為灰度圖,用blur函數進行圖像模糊以降噪,然后用canny函數進行邊緣檢測。

#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;
int main()
{
	Mat SrcPic = imread("lena.jpg");
	imshow("Src Pic", SrcPic);
	Mat DstPic, edge, grayImage;

	//創建與src同類型和同大小的矩陣
	DstPic.create(SrcPic.size(), SrcPic.type());
	
	//將原始圖轉化為灰度圖
	cvtColor(SrcPic, grayImage, COLOR_BGR2GRAY);

	//先使用3*3內核來降噪
	blur(grayImage, edge, Size(3, 3));

	//運行canny算子
	Canny(edge, edge, 3, 9, 3);

	imshow("邊緣提取效果", edge);

	waitKey();
	return 0;
}


運行效果

基礎圖像操作

創建窗口:namedWindow()

void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);

因為有時候需要用到窗口的名字,盡管這個時候還沒有載入圖片,比如我們要在一個窗口上加入一個工具條,我們必須首先知道窗口的名字,這樣才知道在哪里加上這個toolbar。

namedWindow還有一個很重要的功能,如果使用默認參數,窗口是無法自由調整的,如果想實現用戶自由拉伸窗口,可以這么做:

	namedWindow("srcImage", WINDOW_NORMAL);// 注意這個宏,使用WINDOW_NORMAL可以允許用戶自由伸縮窗口大小
	imshow("srcImage", srcImage);

輸出圖像到文件:imwrite()

bool imwrite( const String& filename, InputArray img,const std::vector &params = std::vector ());

創建trackbar以及使用
下面的例子利用trakbar打開多個圖片。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

#define PIC_MAX_NUM 5

int pic_num = 0;

void on_track(int,void*)
{
	char file[10];
	sprintf(file, "lol%d.jpg", pic_num);
	Mat img = imread(file);
	if (!img.data)
	{
		cout << "讀取圖片失敗" << endl;
		return;
	}
	imshow("展示多幅圖片", img);
}

int main()
{
	namedWindow("展示多幅圖片");
	createTrackbar("圖片編號", "展示多幅圖片", &pic_num, PIC_MAX_NUM, on_track);
	on_track(pic_num, NULL);
	waitKey(0);

}

展示一下效果吧!

對一幅圖片進行顏色轉換,轉為灰度圖

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;


int main()
{
	Mat img = imread("lol1.jpg");
	Mat dstImg;
	cvtColor(img, dstImg,COLOR_BGR2GRAY);//從宏名字就可以知道,是彩色圖轉換到灰度圖
	imshow("灰度圖", dstImg);

	waitKey(0);

}

灰度圖

總結一系列常用的數據結構

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

//常見數據結構使用方法總結
int main()
{
	//Mat的用法
	Mat m1(2, 2, CV_8UC3, Scalar(0, 0, 255)); //其中的宏的解釋:CV_[位數][帶符號與否][類型前綴]C[通道數]
	cout << m1 << endl;

	//或者,利用IplImage指針來初始化,將IplImage*轉化為Mat
	IplImage* image = cvLoadImage("lena.jpg");
	Mat mat = cvarrToMat(image);

	//Mat轉IplImage:
	IplImage img = IplImage(mat);

	//或者
	Mat m2;
	m2.create(4, 5, CV_8UC(2));


	//點的表示:Point
	Point p;
	p.x = 1; //x坐標
	p.y = 1; //y坐標

	//或者
	Point p2(1, 1);

	//顏色的表示:Scalar(b,g,r);注意不是rgb,注意對應關系
	Scalar(1, 1, 1);

	//尺寸的表示:Size
	Size(5, 5);// 寬度和高度都是5

	//矩形的表示:Rect,成員變量有x,y,width,height
	Rect r1(0, 0, 100, 60);
	Rect r2(10, 10, 100, 60);
	Rect r3 = r1 | r2; //兩個矩形求交集
	Rect r4 = r1 & r2; //兩個矩形求並集


	waitKey(0);

}

訪問圖片中像素的方式

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

//訪問每個像素,我喜歡使用指針的方式
int main()
{
	Mat img = imread("lol1.jpg");
	for (int i = 0; i < img.rows; i++)
	{
		uchar* data = img.ptr<uchar>(i);  //獲取第i行地址
		for (int j = 0; j < img.cols; j++)
		{
			 printf("%d\n",data[j]);
		}
	}

	waitKey(0);

}

直方圖均衡化

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

//直方圖均衡化
int main()
{
	Mat img = imread("lol3.jpg");
	imshow("原始圖", img);
	Mat dst;
	cvtColor(img, img, CV_RGB2GRAY);
	imshow("灰度圖", img);
	equalizeHist(img, dst);

	imshow("直方圖均衡化", dst);

	waitKey(0);

}

顯然均衡化后的圖片對比度變高了,變得更加明亮!

最后簡單總結一下圖像處理中概念

離散傅里葉變換

圖像高頻部分代表了圖像的細節、紋理信息;低頻代表了圖像的輪廓信息。

低通-》模糊

高通-》銳化

腐蝕和膨脹是針對白色部分(高亮部分)而言的。膨脹就是對圖像高亮部分進行“領域擴張”,效果圖擁有比原圖更大的高亮區域;腐蝕是原圖中的高亮區域被蠶食,效果圖擁有比原圖更小的高亮區域。

開運算:先腐蝕再膨脹,用來消除小物體

閉運算:先膨脹再腐蝕,用於排除小型黑洞

形態學梯度:就是膨脹圖與俯視圖之差,用於保留物體的邊緣輪廓。

頂帽:原圖像與開運算圖之差,用於分離比鄰近點亮一些的斑塊。

黑帽:閉運算與原圖像之差,用於分離比鄰近點暗一些的斑塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM