單純記錄一下之前的代碼
#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/opencv.hpp> #include<opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <cv.h> #include <iostream> #include<fstream> #include <stdio.h> //#include<opencv2/legacy/legacy.hpp> #include <string> #include <vector> #include<opencv2/xfeatures2d.hpp> #include<algorithm> using namespace cv; using namespace std; using namespace cv::xfeatures2d; using namespace cv::ml; int main() { int64 begintime = getTickCount(); ofstream outfile1, outfile2; outfile1.open("matrix.txt"); //outfile2.open("mmright.txt"); //讀入圖像並進行灰度處理 //Mat img1 = imread("D:/SU/Tao13_LF_Depth_Light/DEPTH_FROM_CORR_DEFOC_JPEGONLY/Desk/9168/AllFocus.tif"); //Mat img2 = imread("D:/SU/Tao13_LF_Depth_Light/DEPTH_FROM_CORR_DEFOC_JPEGONLY/Desk/9169/AllFocus.tif"); Mat img1 = imread("panoLeft.tif"); Mat img2 = imread("panoRight.tif"); //第一步,用SIFT算子檢測關鍵點; Ptr<SiftFeatureDetector>detector=SiftFeatureDetector::create(); std::vector<KeyPoint> m_LeftKey, m_RightKey;//構造2個專門由點組成的點向量用來存儲特徵點 detector->detect(img1, m_LeftKey);//將img1圖像中檢測到的特徵點存儲起來放在m_LeftKey中 detector->detect(img2, m_RightKey);//同理 cout << "圖像1特徵點的個數:" << m_LeftKey.size() << endl; cout << "圖像2特徵點的個數:" << m_RightKey.size() << endl; //計算特徵向量 cv::Mat descriptors1, descriptors2;//存放特徵向量的矩陣 detector->compute(img1, m_LeftKey, descriptors1); detector->compute(img2, m_RightKey, descriptors2); //畫出特徵點 Mat img_m_LeftKey, img_m_RightKey; drawKeypoints(img1, m_LeftKey, img_m_LeftKey, Scalar::all(-1), 0); //cvScalar(255,0,0)畫的圈圈是藍色,對應於特徵點的顏色,DrawMatchesFlags::DRAW_RICH_KEYPOINTS表示關鍵點上圓圈的尺寸與特徵的尺度成正比,對應於0,是“標誌位”的意思 drawKeypoints(img2, m_RightKey, img_m_RightKey, Scalar::all(-1), 0); imshow("Keysrc1", img_m_LeftKey); imshow("Keysrc2", img_m_RightKey); imwrite("圖像2的特徵點.tif", img_m_LeftKey); imwrite("圖像3的特徵點.tif", img_m_RightKey); BFMatcher matcher(NORM_L2, false); vector<vector<DMatch>> matches2; vector<DMatch>matches; matcher.match(descriptors1, descriptors2, matches); const float ratio = 0.7; matches.clear(); matcher.knnMatch(descriptors1, descriptors2, matches2, 2); for (int n = 0; n < matches2.size(); n++) { DMatch& bestmatch = matches2[n][0]; DMatch& bettermatch = matches2[n][1]; if (bestmatch.distance < ratio*bettermatch.distance) { matches.push_back(bestmatch); } } cout << "match個數:" << matches.size() << endl; //畫出直接匹配結果 Mat key_matches; drawMatches(img1, m_LeftKey, img2, m_RightKey, matches, key_matches, CV_RGB(255, 0, 255), CV_RGB(0, 255, 0), Mat(), 2); imshow("ratio_matches", key_matches); imwrite("ratio_matches.tif", key_matches); //RANSAC匹配過程 vector<DMatch> m_Matches =matches; //cout<<"m_Matches="<<m_Matches.size()<<endl; // 分配空間 int ptCount = (int)m_Matches.size(); //cout<<"m_Matches="<<ptCount<<endl; Mat p1(ptCount, 2, CV_32F); Mat p2(ptCount, 2, CV_32F); //cout<<"p1="<<p1<<endl; // 把Keypoint轉換爲Mat Point2f pt; for (int i = 0; i<ptCount; i++) { pt = m_LeftKey[m_Matches[i].queryIdx].pt; p1.at<float>(i, 0) = pt.x; p1.at<float>(i, 1) = pt.y; pt = m_RightKey[m_Matches[i].trainIdx].pt; p2.at<float>(i, 0) = pt.x; p2.at<float>(i, 1) = pt.y; } //cout<<"p1="<<p1<<endl;//圖1的匹配點座標 //cout<<"p2="<<p2<<endl;//圖2的匹配點座標 // 用RANSAC方法計算F(基礎矩陣) Mat m_Fundamental; vector<uchar> m_RANSACStatus; // 這個變量用於存儲RANSAC後每個點的狀態 findFundamentalMat(p1, p2, m_RANSACStatus, FM_RANSAC); // 計算內點個數 int OutlinerCount = 0; for (int i = 0; i<ptCount; i++) { if (m_RANSACStatus[i] == 0) // 狀態爲0表示外點 { OutlinerCount++; } } int InlinerCount = ptCount - OutlinerCount; // 計算內點 cout << "內點數爲:" << InlinerCount << endl; cout << "外點數爲:" << OutlinerCount << endl; // 這三個變量用於保存內點和匹配關係 vector<Point2f> m_LeftInlier; vector<Point2f> m_RightInlier; vector<DMatch> m_InlierMatches; m_InlierMatches.resize(InlinerCount); m_LeftInlier.resize(InlinerCount); m_RightInlier.resize(InlinerCount); InlinerCount = 0; float inlier_minRx = img1.cols; //用於存儲內點中右圖最小橫座標,以便後續融合 //cout<<"inlier="<<inlier_minRx<<endl; for (int i = 0; i<ptCount; i++) { if (m_RANSACStatus[i] != 0) { m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0); m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1); m_RightInlier[InlinerCount].x = p2.at<float>(i, 0); m_RightInlier[InlinerCount].y = p2.at<float>(i, 1); m_InlierMatches[InlinerCount].queryIdx = InlinerCount; m_InlierMatches[InlinerCount].trainIdx = InlinerCount; if (m_RightInlier[InlinerCount].x<inlier_minRx) inlier_minRx = m_RightInlier[InlinerCount].x; //存儲內點中右圖最小橫座標 InlinerCount++; } } cout<<"inlier="<<inlier_minRx<<endl;//最小橫座標 // 把內點轉換爲drawMatches可以使用的格式 vector<KeyPoint> key1(InlinerCount); vector<KeyPoint> key2(InlinerCount); KeyPoint::convert(m_LeftInlier, key1); KeyPoint::convert(m_RightInlier, key2); // 顯示計算F過後的內點匹配 Mat OutImage; drawMatches(img1, key1, img2, key2, m_InlierMatches, OutImage, CV_RGB(255, 0, 255), CV_RGB(0, 255, 0)); imshow("RANSAC match features", OutImage); imwrite("RansacMatchb.tif", OutImage); //矩陣H用以存儲RANSAC得到的單應矩陣 Mat H = findHomography(m_LeftInlier, m_RightInlier, RANSAC); outfile1 << H << endl; cout << H << endl; //存儲左圖四角,及其變換到右圖位置 std::vector<Point2f> obj_corners(4); obj_corners[0] = Point(0, 0); obj_corners[1] = Point(img1.cols, 0); obj_corners[2] = Point(img1.cols, img1.rows); obj_corners[3] = Point(0, img1.rows); std::vector<Point2f> scene_corners(4); perspectiveTransform(obj_corners, scene_corners, H); /* //畫出變換後圖像位置 Point2f offset((float)img1.cols, 0); line(OutImage, scene_corners[0] + offset, scene_corners[1] + offset, Scalar(0, 255, 0), 4); line(OutImage, scene_corners[1] + offset, scene_corners[2] + offset, Scalar(0, 255, 0), 4); line(OutImage, scene_corners[2] + offset, scene_corners[3] + offset, Scalar(0, 255, 0), 4); line(OutImage, scene_corners[3] + offset, scene_corners[0] + offset, Scalar(0, 255, 0), 4); imshow("Good Matches & Object detection", OutImage); imwrite("transform.tif", OutImage);*/ int drift = scene_corners[1].x; //儲存偏移量 cout << "scene=" << scene_corners << endl; cout << "scene0=" << scene_corners[0].x << endl; cout << "scene1=" << scene_corners[1].x << endl; cout << "scene2=" << scene_corners[2].x << endl; cout << "scene3=" << scene_corners[3].x << endl; //新建一個矩陣存儲配準後四角的位置 int width = int(max(abs(scene_corners[1].x), abs(scene_corners[2].x)));//等於左圖右邊兩個頂點中橫座標較大的那個 int height = img1.rows; //或者:int height = int(max(abs(scene_corners[2].y), abs(scene_corners[3].y))); float origin_x = 0, origin_y = 0; if (scene_corners[0].x<0) { if (scene_corners[3].x<0) origin_x += min(scene_corners[0].x, scene_corners[3].x); else origin_x += scene_corners[0].x; } width -= int(origin_x);//圖像的寬度變爲左圖變換之後左邊的定點座標小的數值+右邊的橫座標較大的數值 if (scene_corners[0].y<0) { if (scene_corners[1].y) origin_y += min(scene_corners[0].y, scene_corners[1].y); else origin_y += scene_corners[0].y; } //height-=int(origin_y); //imageturn爲變換隻有的左圖的大小 Mat imageturn = Mat::zeros(width, height, img1.type()); cout << "PerspectiveWidth: " << width << endl; cout << "PerspectiveHeight: " << height << endl; cout << "img1.type(): " << img1.type() << endl; //獲取新的變換矩陣,使圖像完整顯示 for (int i = 0; i<4; i++) { scene_corners[i].x -= origin_x; }//相當於把整個圖像往右移動至右圖上,移動距離爲初次變換之後最小的橫座標 Mat H1 = getPerspectiveTransform(obj_corners, scene_corners);//然後移動之後的與右圖再求一次矩陣 //進行圖像變換,顯示效果 warpPerspective(img1, imageturn, H1, Size(width, height)); imshow("image_Perspective", imageturn); imwrite("perpective.tif", imageturn); cout << "origin_x=" << origin_x << endl; cout << "origin_y=" << origin_y << endl; cout << "img1.width=" << img1.cols << endl; cout << "inlier_minRx=" << inlier_minRx << endl; cout << "scene_corners= " << scene_corners << endl; cout << "單應矩陣H=" << H << endl; cout << "變換矩陣H1=" << H1 << endl; //圖像融合 int width_ol = width - int(inlier_minRx - origin_x);//重疊區域的寬 int start_x = int(inlier_minRx - origin_x);//imageturn上的重疊區域的起始座標 右側內點的最小點-origin_x cout << "start_X:" << start_x << endl; /*//imageturn爲左圖圖轉化之後的 重疊區域 開始的橫座標爲右圖上的最小橫座標的內點在imageturn上的座標,右側爲左圖的右邊界 Mat subValue_image = Mat::zeros(imageturn.rows, width_ol, imageturn.type());//創建一個圖用於保存差值圖像 Mat sub1 = imageturn(Rect(start_x, 0, width_ol, imageturn.rows));//start_x 重疊區域的寬 高不變 Mat sub2 = img2(Rect(inlier_minRx, 0, width_ol, img2.rows)); //求兩個圖像插值 absdiff(sub1, sub2, subValue_image); imshow("差值圖", subValue_image); //創建一個mask Mat mask = Mat::zeros(height, width_ol, img1.type());//重疊區域大小 Mat imgL = imageturn(Rect(start_x, 0, width_ol, height)); Mat imgR = img2(Rect(0, 0, width_ol, height)); mask(Rect(0, 0, width_ol*0.5, height)).setTo(255); imshow("mask", mask); Point Center(imgL.cols*0.5, imgL.rows*0.5); Mat resultImage; resultImage.create(imgL.size(), imgL.type()); seamlessClone(imgL, imgR, mask, Center, resultImage, NORMAL_CLONE); imshow("blending", resultImage);*/ uchar* ptr = imageturn.data;//perspective的圖像數據 double alpha = 0, beta = 1;//定義權重 for (int row = 0; row<height; row++) //圖像轉換之後的高度 { //step可以理解爲Mat矩陣中每一行的“步長”,以字節爲基本單位, //每一行中所有元素的字節總量,是累計了一行中所有元素、所有通道、所有通道的elemSize1之後的值; ptr = imageturn.data + row*imageturn.step + (start_x)*imageturn.elemSize(); //data uchar類型的指針,指向Mat數據矩陣的首地址。可以理解爲標示一個房屋的門牌號; for (int col = 0; col<width_ol; col++)//圖像轉換之後寬度 { uchar* ptr_c1 = ptr + imageturn.elemSize1(); uchar* ptr_c2 = ptr_c1 + imageturn.elemSize1(); uchar* ptr2 = img2.data + row*img2.step + (col + int(inlier_minRx))*img2.elemSize(); uchar* ptr2_c1 = ptr2 + img2.elemSize1(); uchar* ptr2_c2 = ptr2_c1 + img2.elemSize1(); alpha = double(col) / double(width_ol); beta = 1 - alpha; if (*ptr == 0 && *ptr_c1 == 0 && *ptr_c2 == 0) {//左圖中轉換了之後的無像素值的黑點,則完全拷貝右側圖的像素值 *ptr = (*ptr2);//該像素第一通道 *ptr_c1 = (*ptr2_c1);//該像素第二通道 *ptr_c2 = (*ptr2_c2);//該像素第三通道 } //如不爲0 *ptr = (*ptr)*beta + (*ptr2)*alpha;//左圖通道1的像素值乘以權重+右側通道1像素值乘以權重 *ptr_c1 = (*ptr_c1)*beta + (*ptr2_c1)*alpha; *ptr_c2 = (*ptr_c2)*beta + (*ptr2_c2)*alpha; ptr += imageturn.elemSize();//指針指向下一個元素 } } imshow("image_overlap", imageturn); Mat img_result = Mat::zeros(height, width + img2.cols - drift, img1.type());//int drift = scene_corners[1].x; cout << "寬:" << width + img2.cols - drift << endl; cout << "高:" << height << endl; uchar* ptr_r = imageturn.data; for (int row = 0; row<height; row++) { ptr_r = img_result.data + row*img_result.step; for (int col = 0; col<imageturn.cols; col++) { uchar* ptr_rc1 = ptr_r + imageturn.elemSize1(); uchar* ptr_rc2 = ptr_rc1 + imageturn.elemSize1(); uchar* ptr = imageturn.data + row*imageturn.step + col*imageturn.elemSize(); uchar* ptr_c1 = ptr + imageturn.elemSize1(); uchar* ptr_c2 = ptr_c1 + imageturn.elemSize1(); *ptr_r = *ptr; *ptr_rc1 = *ptr_c1; *ptr_rc2 = *ptr_c2; ptr_r += img_result.elemSize(); } ptr_r = img_result.data + row*img_result.step + imageturn.cols*img_result.elemSize(); for (int col = imageturn.cols; col<img_result.cols; col++) { uchar* ptr_rc1 = ptr_r + imageturn.elemSize1(); uchar* ptr_rc2 = ptr_rc1 + imageturn.elemSize1(); uchar* ptr2 = img2.data + row*img2.step + (col - imageturn.cols + drift)*img2.elemSize(); uchar* ptr2_c1 = ptr2 + img2.elemSize1(); uchar* ptr2_c2 = ptr2_c1 + img2.elemSize1(); *ptr_r = *ptr2; *ptr_rc1 = *ptr2_c1; *ptr_rc2 = *ptr2_c2; ptr_r += img_result.elemSize(); } } imshow("image_result", img_result); imwrite("panoAll.tif", img_result); //imwrite("14.jpg",img_result); int64 endtime = getTickCount(); cout << "時間:" << (endtime - begintime) / getTickFrequency() << "s" << endl; waitKey(0); return 0; }
SIFT+RANSAC+反距離加權圖像拼接融合(代碼記錄)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.