반응형

OpenCV Python을 사용하여 stitching을 구현해보았습니다. 


스티칭(stitching)은 같은 장소 또는 같은 객체를 촬영한 여러 장의 사진에서 공통적인 부분을 찾아 이미지를 하나로 연결하는 알고리즘입니다. 


결과적으로 아래 이미지처럼 파노라마 이미지가 만들어 집니다.







포스트의 코드는 다음 두 곳의 코드를 기반으로 작성되었습니다. 


https://github.com/opencv/opencv/blob/master/samples/python/find_obj.py 

https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/



영상에 코드 설명이 되어 있습니다.






'''
https://github.com/opencv/opencv/blob/master/samples/python/find_obj.py
https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/

'''

import numpy as np
import cv2 as cv


FLANN_INDEX_LSH    = 6


def anorm2(a):
    return (a*a).sum(-1)
def anorm(a):
    return np.sqrt( anorm2(a) )

def matchKeypoints(keyPoints1, keyPoints2, descriptors1, descriptors2):

    flann_params= dict(algorithm = FLANN_INDEX_LSH,
                      table_number = 6, # 12
                      key_size = 12,     # 20
                      multi_probe_level = 1) #2



    matcher = cv.FlannBasedMatcher(flann_params, {})  # bug : need to pass empty dict (#1329)
    raw_matches = matcher.knnMatch(descriptors1, descriptors2, k = 2) #2

   

    matches = []
    for m in raw_matches:
        if len(m) == 2 and m[0].distance < m[1].distance * 0.79:
            matches.append((m[0].trainIdx, m[0].queryIdx))


    if len(matches) >= 4:

        keyPoints1 = np.float32([keyPoints1[i] for (_, i) in matches])
        keyPoints2 = np.float32([keyPoints2[i] for (i, _) in matches])


        H, status = cv.findHomography(keyPoints1, keyPoints2, cv.RANSAC,4.0)

        print('%d / %d  inliers/matched' % (np.sum(status), len(status)))
    else:
        H, status = None, None
        print('%d matches found, not enough for homography estimation' % len(p1))


    return matches, H, status


 
def drawMatches(image1, image2, keyPoints1, keyPoints2, matches, status):


    h1, w1 = image1.shape[:2]
    h2, w2 = image2.shape[:2]



    img_matching_result = np.zeros((max(h1, h2), w1 + w2, 3), dtype="uint8")



    img_matching_result[0:h2, 0:w2] = image2
    img_matching_result[0:h1, w2:] = image1



    for ((trainIdx, queryIdx), s) in zip(matches, status):

        if s == 1:
            keyPoint2 = (int(keyPoints2[trainIdx][0]), int(keyPoints2[trainIdx][1]))
            keyPoint1 = (int(keyPoints1[queryIdx][0]) + w2, int(keyPoints1[queryIdx][1]))
            cv.line(img_matching_result, keyPoint1, keyPoint2, (0, 255, 0), 1)



    return img_matching_result


def main():


    img1 = cv.imread('.\\images\\B.jpg')
    img2 = cv.imread('.\\images\\A.jpg')
   
   

    gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)
    gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)

   

    detector = cv.BRISK_create()
    keyPoints1, descriptors1 = detector.detectAndCompute(gray1, None)
    keyPoints2, descriptors2 = detector.detectAndCompute(gray2, None)
    print('img1 - %d features, img2 - %d features' % (len(keyPoints1), len(keyPoints2)))


   
    keyPoints1 = np.float32([keypoint.pt for keypoint in keyPoints1])
    keyPoints2 = np.float32([keypoint.pt for keypoint in keyPoints2])
   


    matches, H, status = matchKeypoints(keyPoints1, keyPoints2, descriptors1, descriptors2)



    img_matching_result = drawMatches(img1, img2, keyPoints1, keyPoints2, matches, status)



    result = cv.warpPerspective(img1, H,
        (img1.shape[1] + img2.shape[1], img1.shape[0]))
    result[0:img2.shape[0], 0:img2.shape[1]] = img2


    cv.imshow('result', result)
    cv.imshow('matching result', img_matching_result)

    cv.waitKey()

    print('Done')


if __name__ == '__main__':
    print(__doc__)
    main()
    cv.destroyAllWindows()




OpenCV를 사용하면 2장 이상의 이미지를 입력으로 사용할 수 있습니다. 

OpenCV Python과 OpenCV C++에서 스티칭을 하는 예제입니다 


Python


import numpy as np
import cv2 as cv
import os


path = '.\\images\\'
images = [] 

for root, directories, files in os.walk(path):
   
    for file in files:
        if '.jpg' in file:

            img_input =cv.imread(os.path.join(root, file))

            images.append(img_input)


stitcher = cv.Stitcher.create(cv.Stitcher_PANORAMA)
status, pano = stitcher.stitch(images)

if status != cv.Stitcher_OK:
    print("Can't stitch images, error code = %d" % status)
    exit(-1)

cv.imshow('result', pano)
cv.waitKey(0)
print("stitching completed successfully.")


C++

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching.hpp"

#include <iostream>

using namespace std;
using namespace cv;

bool divide_images = false;
Stitcher::Mode mode = Stitcher::PANORAMA;
vector<Mat> imgs;


int main(int argc, char* argv[])
{

    vector<cv::String> fn;
    glob("./images/*.jpg", fn, false);

    vector<Mat> imgs;
    size_t count = fn.size();
    for (size_t i=0; i<count; i++)
        imgs.push_back(imread(fn[i]));


    Mat pano;
    Ptr<Stitcher> stitcher = Stitcher::create(mode);
    Stitcher::Status status = stitcher->stitch(imgs, pano);

    if (status != Stitcher::OK)
    {
        cout << "Can't stitch images, error code = " << int(status) << endl;
        return EXIT_FAILURE;
    }


    imshow("result", pano);
    waitKey(0);

    cout << "stitching completed successfully\n" << endl;
}




최초작성 2020. 4. 30




반응형

해본 것을 문서화하여 기록합니다.


포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.


제가 쓴 책도 한번 검토해보세요 ^^

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">
  1. thumbnail
    Favicon of https://bskyvision.com BlogIcon bskyvision

    오 관심있던 주제인데 잘보고 갑니다 ㅎㅎ