반응형

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




문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.


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

+ Recent posts