1. 程式人生 > >opencv+影象特徵

opencv+影象特徵

首先明確兩個問題,①為什麼要引進影象特徵?②什麼是影象特徵? 簡而言之,引入影象特徵的目的就是讓計算機能夠識別影象,比如抓取到圖片A中有長鼻子那麼判斷圖片A為大象,抓取到圖片B有長耳朵,那麼可以說圖片B為兔子。那麼什麼是影象特徵?通俗來講,就是影象本身能夠同其他圖片進行區分的一些特徵,這些特徵在進行尺寸變化,或者非複雜仿射變換時依然存在的一些特徵。影象特徵能夠解決的問題包括有識別,定位,追蹤,三維重建等。下面上乾貨

#include <iostream>
#include <opencv2/opencv.hpp>
#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"  
using namespace std;
using namespace cv;
Mat src, dst;
vector<vector<Point>> contours;
void detect_default()
{

//利用影象的表徵識別出影象的缺陷

//利用絕對閾值尋找影象中的黑點
src=imread("default.bmp", 0);
threshold(src, dst, 10, 255, THRESH_BINARY_INV);
Mat draw_src = src.clone();
findContours(dst, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

//這裡並未對輪廓的周長以及面積進行判斷,特殊情況需自行判斷特徵型別
for (int i = 0; i < contours.size(); i++)
{
Rect m_rect = boundingRect(contours[i]);
rectangle(draw_src, Rect(m_rect.x - 5, m_rect.y - 5, m_rect.width + 10, m_rect.height + 10),200,1);
}
imshow("黑點缺陷", draw_src);


//利用相對閾值尋找影象中的凹點
src = imread("default.bmp", 0);
dst = src.clone();
blur(dst, dst, Size(3, 3), Point(-1, -1));
adaptiveThreshold(dst, dst, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 15, 20);
contours.clear();
draw_src = src.clone();
findContours(dst, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
for (int i = 0; i < contours.size(); i++)
{
Rect m_rect = boundingRect(contours[i]);
rectangle(draw_src, Rect(m_rect.x - 8, m_rect.y - 8, m_rect.width + 16, m_rect.height + 16), 200, 1);
}
imshow("凹缺陷", draw_src);
waitKey(0);
}
void model_match()
{
//影象的相關性,既指影象自身畫素間的相關性,比如尋找連通區域。也可指不同影象之間的相關性,比如模板匹配
//下面用模板匹配,來尋找圖中的匹配物
src = imread("dota2.jpg", 0);
Mat draw_src=imread("dota2.jpg");
imshow("原圖", src);
Mat model = imread("model.jpg",0);
imshow("模型", model);
Mat res;
matchTemplate(src, model, res, 0);
Point min_point,max_point;
double match_value;
minMaxLoc(res, &match_value, NULL, &min_point, &max_point);
rectangle(draw_src, Rect(min_point.x, min_point.y, model.cols, model.rows), Scalar(0,0,255), 1);
}
void pca_calc()
{
//談到pca的時候,我們做個假設,假設影象是由10塊積木搭成的,其中第一塊的一塊佔據了這個影象的80%
//第二塊佔據了影象的10%,第三塊佔據了影象的5%,依次類推,然後,我們把這張圖拆成10塊積木,拿出前兩塊拼好
//然後我說,這兩塊是可以代表這幅圖的,顯然這是個偽命題,但從一定程度來說,這兩塊的確能代表整幅圖。這就是PCA的
//思想,我們用svd對一張圖進行分解,分解出來的就是影象的特徵,也可以說是奇異值,然後對這些奇異值進行重組,
//這就能起到降維的作用

Mat img = imread("timg.jpg", IMREAD_GRAYSCALE);
imshow("原圖", img);
img.convertTo(img, CV_32FC1);//轉換為float型別  
string tile = "壓縮比率";
Mat U, W, VT;
SVD svd;
//這裡進行奇異值分解
svd.compute(img, W, U, VT);

//將矩陣進行壓縮  
//原始資料進行壓縮之後是 m*m m*n n*n  
//由於特徵值在前幾行中佔有的比率是比較大的,所以,僅僅選擇前幾行(r)作為好的特徵值  
//那麼分解的結果就變為 m*r r*r r*n 這樣的形式  
double radio = 1;//壓縮比率  
int rows = radio*img.rows;
Mat WROI = Mat::zeros(rows, rows, CV_32FC1);//W矩陣的大小  
//填充舉著WROI,這裡的i就是控制奇異值的輸出量,奇異值從大到小排列,這裡的i去0到rows,就是完美復原,取0到30就處於原圖近似
for (int i = 0; i < 30; ++i)
{
WROI.at<float>(i, i) = W.at<float>(i);
}
Mat UROI = U.colRange(0, rows);//主要注意的是,colrange中不包含End  
Mat VTROI = VT.rowRange(0, rows);
Mat Result = UROI*WROI*VTROI;
Result.convertTo(Result, CV_8UC1);
namedWindow(tile);
imshow(tile, Result);
waitKey(0);
}
void feature_match()
{
//大腦在接收視覺的時候,他會關注影象中有這突變的點,不管是畫素值上的突變,還是輪廓上的突變,
//opencv也有類似的演算法,他能自動幫你找出這些突變的點,surf是其中一個,下面採用的是surf的一個變種演算法SIFT
//sift比起surf的一個好處是他能夠解決遮擋以及背景混亂的問題


Mat image01 = imread("view1.png", 1);
Mat image02 = imread("view2.png", 1);
imshow("p2", image01);
imshow("p1", image02);


//灰度圖轉換  
Mat image1, image2;
cvtColor(image01, image1, CV_RGB2GRAY);
cvtColor(image02, image2, CV_RGB2GRAY);




//提取特徵點    
SurfFeatureDetector surfDetector(2000);  // 海塞矩陣閾值,在這裡調整精度,值越大點越少,越精準 
vector<KeyPoint> keyPoint1, keyPoint2;
surfDetector.detect(image1, keyPoint1);
surfDetector.detect(image2, keyPoint2);


//特徵點描述,為下邊的特徵點匹配做準備    
SurfDescriptorExtractor SurfDescriptor;
Mat imageDesc1, imageDesc2;
SurfDescriptor.compute(image1, keyPoint1, imageDesc1);
SurfDescriptor.compute(image2, keyPoint2, imageDesc2);


FlannBasedMatcher matcher;
vector<vector<DMatch> > matchePoints;
vector<DMatch> GoodMatchePoints;


vector<Mat> train_desc(1, imageDesc1);
matcher.add(train_desc);
matcher.train();


matcher.knnMatch(imageDesc2, matchePoints, 2);
cout << "total match points: " << matchePoints.size() << endl;


// Lowe's algorithm,獲取優秀匹配點
for (int i = 0; i < matchePoints.size(); i++)
{
if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance)
{
GoodMatchePoints.push_back(matchePoints[i][0]);
}
}


Mat first_match;
drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
imshow("first_match ", first_match);
waitKey();




}
int main()
{
//基於畫素變化的缺陷查詢
detect_default();
//基於特徵向量的svd以及pca
pca_calc();
//基於特徵點的特徵點匹配
feature_match();
//基於統計特徵:輪廓的周長&面積,畫素的均值&偏差,全域性但不侷限於全域性上的直方圖,基於卷積的描繪子等
model_match();

namedWindow("main", WINDOW_AUTOSIZE);


return 0;






}

下面這是detect_deafult()的效果


這是pca_calc()的效果圖



下面是feature_match()的效果圖


下面是model_match()的效果圖