基於OpenCV全景拼接(Python)SIFT/SURF

 

一.實驗內容:python

利用sift算法,實現全景拼接算法,將給定的兩幅圖片拼接爲一幅.算法

二.實驗環境:數據庫

主機配置: CPU :intel core i5-7300 2.50GHZ RAM :8.0GB數組

運行環境:win10 64位操做系統app

開發環境:python3.7dom

 

三.核心算法原理:ide

1.SIFT算法函數

 

SIFT,即尺度不變特徵變換(Scale-invariant feature transform,SIFT),是用於圖像處理領域的一種描述。這種描述具備尺度不變性,可在圖像中檢測出關鍵點,是一種局部特徵描述子。oop

 

特色:性能

1.SIFT特徵是圖像的局部特徵,其對旋轉、尺度縮放、亮度變化保持不變性,對視角變化、仿射變換、噪聲也保持必定程度的穩定性;

2. 區分性(Distinctiveness)好,信息量豐富,適用於在海量特徵數據庫中進行快速、準確的匹配;

3. 多量性,即便少數的幾個物體也能夠產生大量的SIFT特徵向量;

4.高速性,經優化的SIFT匹配算法甚至能夠達到實時的要求;

5.可擴展性,能夠很方便的與其餘形式的特徵向量進行聯合。

特徵檢測基本步驟:

1.尺度空間極值檢測:

搜索全部尺度上的圖像位置。經過高斯微分函數來識別潛在的對於尺度和旋轉不變的興趣點。

2. 關鍵點定位

在每一個候選的位置上,經過一個擬合精細的模型來肯定位置和尺度。關鍵點的選擇依據於它們的穩定程度。

3. 方向肯定

基於圖像局部的梯度方向,分配給每一個關鍵點位置一個或多個方向。全部後面的對圖像數據的操做都相對於關鍵點的方向、尺度和位置進行變換,從而提供對於這些變換的不變性。

4. 關鍵點描述

在每一個關鍵點周圍的鄰域內,在選定的尺度上測量圖像局部的梯度。這些梯度被變換成一種表示,這種表示容許比較大的局部形狀的變形和光照變化。

SIFT特徵匹配階段: 

第一階段:SIFT特徵的生成,即從多幅圖像中提取對尺度縮放、旋轉、亮度變化無關的特徵向量。

第二階段:SIFT特徵向量的匹配。

SIFT特徵的生成通常包括如下幾個步驟:

1. 構建尺度空間,檢測極值點,得到尺度不變性。

2. 特徵點過濾並進行精肯定位。

3. 爲特徵點分配方向值。

4. 生成特徵描述子。

當兩幅圖像的SIFT特徵向量生成之後,下一步就能夠採用關鍵點特徵向量的歐式距離來做爲兩幅圖像中關鍵點的類似性斷定度量。取圖1的某個關鍵點,經過遍歷找到圖像2中的距離最近的兩個關鍵點。在這兩個關鍵點中,若是最近距離除以次近距離小於某個閾值,則斷定爲一對匹配點。

  1. Lowe’s算法:

爲了進一步篩選匹配點,來獲取優秀的匹配點,這就是所謂的「去粗取精」。通常會採用Lowe’s算法來進一步獲取優秀匹配點。

   爲了排除由於圖像遮擋和背景混亂而產生的無匹配關係的關鍵點,SIFT的做者Lowe提出了比較最近鄰距離與次近鄰距離的SIFT匹配方式:取一幅圖像中的一個SIFT關鍵點,並找出其與另外一幅圖像中歐式距離最近的前兩個關鍵點,在這兩個關鍵點中,若是最近的距離除以次近的距離獲得的比率ratio少於某個閾值T,則接受這一對匹配點。由於對於錯誤匹配,因爲特徵空間的高維性,類似的距離可能有大量其餘的錯誤匹配,從而它的ratio值比較高。顯然下降這個比例閾值T,SIFT匹配點數目會減小,但更加穩定,反之亦然。

   Lowe推薦ratio的閾值爲0.8,但做者對大量任意存在尺度、旋轉和亮度變化的兩幅圖片進行匹配,結果代表ratio取值在0. 4~0. 6 之間最佳,小於0. 4的不多有匹配點,大於0. 6的則存在大量錯誤匹配點,因此建議ratio的取值原則以下:

ratio=0. 4:對於準確度要求高的匹配;

ratio=0. 6:對於匹配點數目要求比較多的匹配;

ratio=0. 5:通常狀況下。

3.RANSAC算法

   隨機抽樣一致算法(RANdom SAmple Consensus,RANSAC),採用迭代的方式從一組包含離羣的被觀測數據中估算出數學模型的參數。RANSAC算法假設數據中包含正確數據和異常數據(或稱爲噪聲)。正確數據記爲內點(inliers),異常數據記爲外點(outliers)。同時RANSAC也假設,給定一組正確的數據,存在能夠計算出符合這些數據的模型參數的方法。該算法核心思想就是隨機性和假設性,隨機性是根據正確數據出現機率去隨機選取抽樣數據,根據大數定律,隨機性模擬能夠近似獲得正確結果。假設性是假設選取出的抽樣數據都是正確數據,而後用這些正確數據經過問題知足的模型,去計算其餘點,而後對此次結果進行一個評分。

算法基本思想

1)要獲得一個直線模型,須要兩個點惟一肯定一個直線方程。因此第一步隨機選擇兩個點。

2)經過這兩個點,能夠計算出這兩個點所表示的模型方程y=ax+b。

3)將全部的數據點套到這個模型中計算偏差。

4)找到全部知足偏差閾值的點。

5)而後咱們再重複(1)~(4)這個過程,直到達到必定迭代次數後,選出那個被支持的最多的模型,做爲問題的解。

 

四.處理步驟:

 

Step1:從輸入的兩張圖片裏檢測關鍵點、提取局部不變特徵。(sift)

Step2:匹配的兩幅圖像之間的特徵(Lowe’s算法)

Step3:使用RANSAC算法利用匹配特徵向量估計單映矩陣(homography matrix)。

Step4:利用Step3獲得的單映矩陣應用扭曲變換。

 

具體步驟分析見 . 步驟分析

 

五.核心代碼:

# -*- coding: utf-8 -*-
""" Created on Fri Sep 27 22:29:53 2019 @author: erio """

import numpy as np import imutils import cv2 import time class Stitcher: def __init__(self): # determine if we are using OpenCV v3.X
        self.isv3 = imutils.is_cv3() def stitch(self, images, ratio=0.75, reprojThresh=4.0, showMatches=False): # unpack the images, then detect keypoints and extract
        # local invariant descriptors from them
 (imageB, imageA) = images start = time.time() (kpsA, featuresA) = self.detectAndDescribe(imageA) end = time.time() print('%.5f s' %(end-start)) (kpsB, featuresB) = self.detectAndDescribe(imageB) # match features between the two images
        start = time.time() M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh) end = time.time() print('%.5f s' %(end-start)) # if the match is None, then there aren't enough matched
        # keypoints to create a panorama
        if M is None: return None # otherwise, apply a perspective warp to stitch the images
        # together
        (matches, H, status) = M start = time.time() result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0])) result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB end = time.time() print('%.5f s' %(end-start)) # check to see if the keypoint matches should be visualized
        if showMatches: start = time.time() vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status) end = time.time() print('%.5f s' %(end-start)) # return a tuple of the stitched image and the
            # visualization
            return (result, vis) # return the stitched image
        return result #接收照片,檢測關鍵點和提取局部不變特徵
    #用到了高斯差分(Difference of Gaussian (DoG))關鍵點檢測,和SIFT特徵提取
    #detectAndCompute方法用來處理提取關鍵點和特徵
    #返回一系列的關鍵點
    def detectAndDescribe(self, image): # convert the image to grayscale
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # check to see if we are using OpenCV 3.X
        if self.isv3: # detect and extract features from the image
            descriptor = cv2.xfeatures2d.SIFT_create() (kps, features) = descriptor.detectAndCompute(image, None) # otherwise, we are using OpenCV 2.4.X
        else: # detect keypoints in the image
            detector = cv2.FeatureDetector_create("SIFT") kps = detector.detect(gray) # extract features from the image
            extractor = cv2.DescriptorExtractor_create("SIFT") (kps, features) = extractor.compute(gray, kps) # convert the keypoints from KeyPoint objects to NumPy
        # arrays
        kps = np.float32([kp.pt for kp in kps]) # return a tuple of keypoints and features
        return (kps, features) #matchKeypoints方法須要四個參數,第一張圖片的關鍵點和特徵向量,第二張圖片的關鍵點特徵向量。
    #David Lowe’s ratio測試變量和RANSAC重投影門限也應該被提供。
    def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh): # compute the raw matches and initialize the list of actual
        # matches
        matcher = cv2.DescriptorMatcher_create("BruteForce") rawMatches = matcher.knnMatch(featuresA, featuresB, 2) matches = [] # loop over the raw matches
        for m in rawMatches: # ensure the distance is within a certain ratio of each
            # other (i.e. Lowe's ratio test)
            if len(m) == 2 and m[0].distance < m[1].distance * ratio: matches.append((m[0].trainIdx, m[0].queryIdx)) # computing a homography requires at least 4 matches
        if len(matches) > 4: # construct the two sets of points
            ptsA = np.float32([kpsA[i] for (_, i) in matches]) ptsB = np.float32([kpsB[i] for (i, _) in matches]) # compute the homography between the two sets of points
            (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh) # return the matches along with the homograpy matrix
            # and status of each matched point
            return (matches, H, status) # otherwise, no homograpy could be computed
        return None #連線畫出兩幅圖的匹配
    def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status): # initialize the output visualization image
        (hA, wA) = imageA.shape[:2] (hB, wB) = imageB.shape[:2] vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8") vis[0:hA, 0:wA] = imageA vis[0:hB, wA:] = imageB # loop over the matches
        for ((trainIdx, queryIdx), s) in zip(matches, status): # only process the match if the keypoint was successfully
            # matched
            if s == 1: # draw the match
                ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1])) ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1])) cv2.line(vis, ptA, ptB, (0, 255, 0), 1) # return the visualization
        return vis if __name__ == '__main__': # load the two images and resize them to have a width of 400 pixels # (for faster processing)
    imageA = cv2.imread('D:/test1.jpg') imageB = cv2.imread('D:/test2.jpg') #imageA = imutils.resize(imageA, width=400) #imageB = imutils.resize(imageB, width=400) # stitch the images together to create a panorama # showMatches=True 展現兩幅圖像特徵的匹配,返回vis
    start = time.time() stitcher = Stitcher() (result, vis) = stitcher.stitch([imageA, imageB], showMatches=True) # show the images
    end = time.time() print('%.5f s' %(end-start)) cv2.imwrite('D:/vis1.jpg', vis) cv2.imwrite('D:/result.jpg', result)

 

六.步驟分析:

概述:

Sitich調用detectAndDescribe檢測兩張圖片裏關鍵點、提取局部不變特徵。

有了關鍵點和特徵,sitich調matchKeypoints方法來匹配兩張圖片裏的特徵。若是返回匹配的M爲None,就是由於現有的關鍵點不足以匹配生成全景圖。假設M不返回None,拆包返回元組,包含關鍵點匹配matches、從RANSAC算法中獲得的最優單映射變換矩陣H以及最後的單映計算狀態列表status,用來代表那些已經成功匹配的關鍵點。

 

有了最優單映射變換矩陣H後,就可將兩張圖片「縫合起來」。stitch調用cv2.warpPerspective進行縫合。這樣,就返回一個拼接的圖片。

最後sitich調用drawMatches函數用來將兩張圖片關鍵點的匹配可視化

函數分析:

detectAndDescribe

detectAndDescribe方法用來接收照片,檢測關鍵點和提取局部不變特徵。實現中用到了高斯差分(Difference of Gaussian (DoG))關鍵點檢測,和SIFT特徵提取。

參數爲單個的圖片。

返回值kps爲keypoints,features爲局部不變特徵。

檢測是否用了OpenCV 3.X,若是是,就用cv2.xfeatures2d.SIFT_create方法來實現DoG關鍵點檢測和SIFT特徵提取。detectAndCompute方法用來處理提取關鍵點和特徵。

若是OpenCV2.4cv2.FeatureDetector_create方法來實現關鍵點的檢測(DoG)。detect方法返回一系列的關鍵點。用SIFT關鍵字來初始化cv2.DescriptorExtractor_create,設置SIFT特徵提取。調用extractor的compute方法返回一組關鍵點周圍量化檢測的特徵向量。

最後,關鍵點從KeyPoint對象轉換爲NumPy數後返回給調用函數。

 

matchKeypoints

用於匹配兩張圖片的特徵

matchKeypoints方法須要個參數,第一張圖片的關鍵點和特徵向量,第二張圖片的關鍵點特徵向量David Lowe’s ratio測試變量ratioRANSAC重投影門限reprojThresh。

返回值爲matches, H, status。分別爲匹配的關鍵點matches,最優單映射變換矩陣 H(3x3),單映計算的狀態列表status用於表示已經成功匹配的關鍵點。

匹配特徵過程: 循環每張圖片的描述子,計算距離,最後找到每對描述子的最小距離。

由於這是計算機視覺中的一個很是廣泛的作法,OpenCV已經內置了cv2.DescriptorMatcher_create方法,用來匹配特徵。BruteForce參數表示咱們可以更詳盡計算兩張圖片直接的歐式距離,以此來尋找每對描述子的最短距離。

knnMatch方法是K=2的兩個特徵向量的k-NN匹配(k-nearest neighbors algorithm,K近鄰算法),代表每一個匹配的前兩名做爲特徵向量返回。之因此咱們要的是匹配的前兩個而不是隻有第一個,是由於咱們須要用David Lowe’s ratio來測試假匹配而後作修剪。

以後,用第79行的rawMatches來計算每對描述子,可是這些描述子多是錯誤的,也就是這是圖片不是真正的匹配。去修剪這些有誤的匹配,咱們能夠運用 Lowe’s ratio測試特別的來循環rawMatches,這是用來肯定高質量的特徵匹配。正常的Lowe’s ratio 值在[0.7,0.8].

咱們用Lowe’s ratio 測試獲得matches的值後,咱們就能夠計算這兩串關鍵點之間的單映性。 計算兩串關鍵點的單映性須要至少四個匹配。爲了得到更爲可信的單映性,咱們至少須要超過四個匹配點。

調用cv2.findHomography計算H和status。

 

 

drawMatches

drawMatches用來將兩張圖片關鍵點的匹配可視化。

參數爲原始圖片A,B,關鍵點kpsA,kpsB,匹配的關鍵點matches以及單映的狀態列表status。

返回值爲將兩張圖片中的匹配點用直線鏈接起來的圖片。

運用參數,咱們能夠經過將兩張圖片匹配的關鍵點N和關鍵點M畫直線鏈接,並返回包含這些直線的圖片實現可視化。

Stitch

參數

images。傳入圖片的列表,縫合在一塊兒造成全景圖。注意傳入的圖像是從左到右的順序。若是提供的不是這樣的順序,程序仍然能夠跑,可是輸出全景是不正確的。ratio ,用於特徵匹配時David Lowe比率測試,reprojthresh 是RANSAC算法中最大像素「迴旋的餘地」,最後的showMatches,是一個布爾類型的值,用於代表是否調用drawMatches進行關鍵點匹配可視化

返回值,返回拼接好的圖片result已經用於可視化匹配關鍵點的圖片vis.

Sitich調用detectAndDescribe檢測兩張圖片裏關鍵點、提取局部不變特徵。

調matchKeypoints方法來匹配兩張圖片裏的特徵

調用cv2.warpPerspective進行縫合。須要三個參數:想要「縫合」上來的照片(本程序裏的右邊的圖片);還有3*3的最優單映射轉換矩陣H;最後就是塑造出要輸出的照片。咱們獲得輸出圖像的寬是兩圖片之和,高即爲第二張圖像的高度。

調用drawMatches函數用來將兩張圖片關鍵點的匹配可視化

 

  1. 結果展現:

給定圖片爲老師提供的IMG_201901.jpg和IMG_201901.jpg,重命名爲test1.jpg,test2.jpg。

輸出拼接好的圖片爲rusult.jpg。

展現關鍵點匹配的圖片vis.jpg。

 

傳入圖片

 

 

 

 

 

 

 

test1.jpg

 

test2.jpg

 

 

 

 

 

 

拼接好的圖片:result.jpg

 

 

 

可視化關鍵點匹配:Vis.jpg

 

 

 

8.性能分析:

時間:

項目運行總時間304.79945 s

單張圖片detectAndDescribe檢測關鍵點、提取局部不變特徵用時8.31044 s

matchKeypoints匹配兩張圖片裏的特徵用時292.67749 s

cv2.warpPerspective縫合圖像用時0.27427 s

drawMatches創建直線關鍵點的匹配可視化用時0.33913 s

可見matchKeypoints計算量最大

Lowe’s ratio循環消耗時間較長,同時cv2.findHomography計算最優單映矩陣H與status佔用必定時間。

 

時間優化:

使用比SIFT快的SURF方法,

調節它的參數,減小一些關鍵點,只獲取64維而不是128維的向量等,加快速度。

 

圖像拼接質量:

拼接比較流暢,肉眼判斷爲一張圖片。

缺陷在於看到有一條像摺痕同樣的線條,這個就是兩個圖片的拼接線主要緣由是光線的變化。

 

拼接質量優化:

對於銜接處存在的縫隙問題,有一個解決辦法是按必定權重疊加圖1和圖2的重疊部分,在重疊處圖2的比重是1,向着圖1的方向,越遠離銜接處,圖1的權重愈來愈大,圖2的權重愈來愈低,實現平穩過渡

 

優化:

 

時間優化:使用比SIFT快的SURF方法,使用Hessian算法檢測關鍵點。在使用SURF時,還能夠調節它的參數,減小一些關鍵點,只獲取64維而不是128維的向量等,加快速度。

拼接質量優化:對第一張圖和它的重疊區作一些加權處理,重疊部分,離左邊圖近的,左邊圖的權重就高一些,離右邊近的,右邊旋轉圖的權重就高一些,而後二者相加,實現平滑過渡。

思路和方法


思路
提取要拼接的兩張圖片的特徵點、特徵描述符;
將兩張圖片中對應的位置點找到,匹配起來;
若是找到了足夠多的匹配點,就能將兩幅圖拼接起來,拼接前,可能須要將第二幅圖透視旋轉一下,利用找到的關鍵點,將第二幅圖透視旋轉到一個與第一幅圖相同的能夠拼接的角度;
進行拼接;
進行拼接後的一些處理,讓效果看上去更好。


實現方法
提取圖片的特徵點、描述符,可使用opencv建立一個SIFT對象,SIFT對象使用DoG方法檢測關鍵點,並對每一個關鍵點周圍的區域計算特徵向量。在實現時,可使用比SIFT快的SURF方法,使用Hessian算法檢測關鍵點。由於只是進行全景圖拼接,在使用SURF時,還能夠調節它的參數,減小一些關鍵點,只獲取64維而不是128維的向量等,加快速度。
在分別提取好了兩張圖片的關鍵點和特徵向量之後,能夠利用它們進行兩張圖片的匹配。在拼接圖片中,可使用Knn進行匹配,可是使用FLANN快速匹配庫更快,圖片拼接,須要用到FLANN的單應性匹配。
單應性匹配完以後能夠得到透視變換H矩陣,用這個的逆矩陣來對第二幅圖片進行透視變換,將其轉到和第一張圖同樣的視角,爲下一步拼接作準備。
透視變換完的圖片,其大小就是最後全景圖的大小,它的右邊是透視變換之後的圖片,左邊是黑色沒有信息。拼接時能夠比較簡單地處理,經過numpy數組選擇直接把第一張圖加到它的左邊,覆蓋掉重疊部分,獲得拼接圖片,這樣作很是快,可是最後效果不是很好,中間有一條分割痕跡很是明顯。使用opencv指南中圖像金字塔的代碼對拼接好的圖片進行處理,整個圖片平滑了,中間的縫仍是特別突兀。
直接拼效果不是很好,能夠把第一張圖疊在左邊,可是對第一張圖和它的重疊區作一些加權處理,重疊部分,離左邊圖近的,左邊圖的權重就高一些,離右邊近的,右邊旋轉圖的權重就高一些,而後二者相加,使得過渡是平滑地,這樣看上去效果好一些,速度就比較慢。若是是用SURF來作,時間主要畫在平滑處理上而不是特徵點提取和匹配。


python_opencv中主要使用的函數
基於python 3.7和對應的python-opencv
cv2.xfeatures2d.SURF_create ([hessianThreshold[, nOctaves[, nOctaveLayers[, extended[, upright]]]]])
  該函數用於生成一個SURF對象,在使用時,爲提升速度,能夠適當提升hessianThreshold,以減小檢測的關鍵點的數量,能夠extended=False,只生成64維的描述符而不是128維,令upright=True,不檢測關鍵點的方向。
cv2.SURF.detectAndCompute(image, mask[, descriptors[, useProvidedKeypoints]])
  該函數用於計算圖片的關鍵點和描述符,須要對兩幅圖都進行計算。
flann=cv2.FlannBasedMatcher(indexParams,searchParams)
match=flann.knnMatch(descrip1,descrip2,k=2)
  flann快速匹配器有兩個參數,一個是indexParams,一個是searchParams,都用手冊上建議的值就能夠。在建立了匹配器獲得匹配數組match之後,就能夠參考Lowe給出的參數,對匹配進行過濾,過濾掉很差的匹配。其中返回值match包括了兩張圖的描述符距離distance 、訓練圖(第二張)的描述符索引trainIdx 、查詢的圖(第一張)的描述符索引queryIdx 這幾個屬性。
M,mask=cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]])
  這個函數實現單應性匹配,返回的M是一個矩陣,即對關鍵點srcPoints作M變換能變到dstPoints的位置。
warpImg=cv2.warpPerspective(src,np.linalg.inv(M),dsize[,dst[,flags[,borderMode[,borderValue]]]])
  用這個函數進行透視變換,變換視角。src是要變換的圖片,np.linalg.inv(M)是④中M的逆矩陣,獲得方向一致的圖片。
a=b.copy() 實現深度複製,Python中默認是按引用複製,a=b是a指向b的內存。
draw_params = dict(matchColor = (0,255,0),singlePointColor = (255,0,0),matchesMask = matchMask,flags = 2),img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
  使用drawMatches能夠畫出匹配的好的關鍵點,matchMask是比較好的匹配點,之間用綠色線鏈接起來。

 

核心代碼

import cv2 import numpy as np from matplotlib import pyplot as plt import time MIN = 10 starttime=time.time() img1 = cv2.imread('1.jpg') #query
img2 = cv2.imread('2.jpg') #train

#img1gray=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY) #img2gray=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
surf=cv2.xfeatures2d.SURF_create(10000,nOctaves=4,extended=False,upright=True) #surf=cv2.xfeatures2d.SIFT_create()#能夠改成SIFT
kp1,descrip1=surf.detectAndCompute(img1,None) kp2,descrip2=surf.detectAndCompute(img2,None) FLANN_INDEX_KDTREE = 0 indexParams = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) searchParams = dict(checks=50) flann=cv2.FlannBasedMatcher(indexParams,searchParams) match=flann.knnMatch(descrip1,descrip2,k=2) good=[] for i,(m,n) in enumerate(match): if(m.distance<0.75*n.distance): good.append(m) if len(good)>MIN: src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2) ano_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,1,2) M,mask=cv2.findHomography(src_pts,ano_pts,cv2.RANSAC,5.0) warpImg = cv2.warpPerspective(img2, np.linalg.inv(M), (img1.shape[1]+img2.shape[1], img2.shape[0])) direct=warpImg.copy() direct[0:img1.shape[0], 0:img1.shape[1]] =img1 simple=time.time() #cv2.namedWindow("Result", cv2.WINDOW_NORMAL) #cv2.imshow("Result",warpImg)
        rows,cols=img1.shape[:2] for col in range(0,cols): if img1[:, col].any() and warpImg[:, col].any():#開始重疊的最左端
                left = col break
        for col in range(cols-1, 0, -1): if img1[:, col].any() and warpImg[:, col].any():#重疊的最右一列
                right = col break res = np.zeros([rows, cols, 3], np.uint8) for row in range(0, rows): for col in range(0, cols): if not img1[row, col].any():#若是沒有原圖,用旋轉的填充
                    res[row, col] = warpImg[row, col] elif not warpImg[row, col].any(): res[row, col] = img1[row, col] else: srcImgLen = float(abs(col - left)) testImgLen = float(abs(col - right)) alpha = srcImgLen / (srcImgLen + testImgLen) res[row, col] = np.clip(img1[row, col] * (1-alpha) + warpImg[row, col] * alpha, 0, 255) warpImg[0:img1.shape[0], 0:img1.shape[1]]=res final=time.time() img3=cv2.cvtColor(direct,cv2.COLOR_BGR2RGB) plt.imshow(img3,),plt.show() img4=cv2.cvtColor(warpImg,cv2.COLOR_BGR2RGB) plt.imshow(img4,),plt.show() print("simple stich cost %f"%(simple-starttime)) print("\ntotal cost %f"%(final-starttime)) cv2.imwrite("simplepanorma.png",direct) cv2.imwrite("bestpanorma.png",warpImg) else: print("not enough matches!")

效果圖:

 

 

 

 

 

 

參考

 

https://www.pyimagesearch.com/

https://cloud.tencent.com/developer/article/1178958

 

 https://blog.csdn.net/qq_37734256/article/details/86745451

相關文章
相關標籤/搜索