[ptyhon] 자동으로 그림 편집을 빈틈없이 조합합니다

하고 싶은 일


트림된 두 이미지를 자동으로 연결하여 이음매를 자연스럽게 만듭니다.

아이디어


위와 같은 측면 이미지와 아래쪽 이미지의 끝부분을 기점으로 천천히 영역을 축소하여 비교한다.
일치도가 가장 높은 영역 이미지를 공통 영역으로 결합합니다.

전제 조건

  • pillow로 읽기
  • 수직 방향에서 결합
  • 가로 방향 미리 정렬
  • 너비도 가지런
  • python3.8
  • 흐름(배운 것)


    1. 이미지 자르기
    2. 이미지 비교
    3. 이미지 연결
    4. 계산량을 줄이기 위해

    1. 이미지 자르기


    이번에는 pillow 형식으로 Image.crop()로 편집했습니다.
    Image.crop((トリミング左端のx座標, 上端のy座標, 右端のx座標, 下端のy座標))
    
    매개 변수는 반드시 원조로 지정해야 하며, 괄호 '(') '는 이중이므로 주의해야 한다.계산량을 줄이기 위해 위쪽과 아래쪽 중 비교적 작은 쪽을 비교 시작 구역으로 삼아 1px를 조금씩 줄인다.(예제 코드에서 위쪽 이미지가 크면 높이 차이를 변수 dif h에 저장하여 위쪽 좌표를 자르는 데 사용됨)

    2. 이미지 비교


    재단된 그림을 Opencv 형식으로 변환하고 cv2.matchTemplate()로 그림을 비교합니다.
    cv2.matchTemplate(比較する画像1, 比較する画像2, マッチングのモード)
    
    일치하는 모델은 여러 가지가 있지만 이번 용도는 무엇이든 될 수 있다고 생각해서 비교적 표준적인cv2.TM_CCOEFF_NORMED을 사용했다.
    matchTemplate의 출력은 일치도를 명암으로 표시하는 그레이스케일 이미지 (비슷함) 이기 때문에 cv2.minMaxLoc() 를 사용하여 최대치 = 이 이미지의 일치 평가 결과를 얻습니다.
    cv2.minMaxLoc(評価するグレースケール画像)[1]
    
    minmaxLoc의 반환값은 두 번째 최대값이 저장되어 있기 때문에 [1]에서 최대값을 꺼냅니다.(이미지 템플릿 일치 통과이 페이지 등 상세한 설명)
    구역을 바꾸는 동시에 for문으로 상술한 내용을 반복하여 일치 평가 결과의 가장 큰 위치를 찾아낸다.

    3. 이미지 연결


    제가 이 페이지에서 인용할 수 있도록 허락해 주십시오.
    https://note.nkmk.me/python-pillow-concat-images/
    def get_concat_v(im1, im2):
        dst = Image.new('RGB', (im1.width, im1.height + im2.height))
        dst.paste(im1, (0, 0))
        dst.paste(im2, (0, im1.height))
        return dst
    
    pillow 형식의 이미지에서 Image.new()로 영역을 만들고 Image.paste()로 연결된 이미지를 붙여넣습니다.

    4. 계산량을 줄이기 위해


    한번 해 보면 그림의 크기가 클수록 시간이 걸린다는 것을 알 수 있다.
    이번에는 위쪽 이미지와 아래쪽 이미지가 더 작은 쪽을 비교 시작 구역 사이즈로 그레이스케일링합니다.
    이번에는 채택하지 않았지만, 사이즈 조절을 통한 이미지 비교를 통해 비교를 제한하는 영역은 일정 평가치를 초과하면 비교를 끝내는 등의 방식으로 계산량을 줄일 수 있다.

    완료 코드

    import numpy as np
    from PIL import Image
    import cv2
    
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    def auto_img_concat_v(upper_img, under_img):
    
        max_res_num = 0  # マッチング評価結果の最大値を保存
        over_pixel = 0  # マッチング評価最大時の重なりピクセル数を保存
    
        img_w = upper_img.width
        upper_h = upper_img.height
        under_h = under_img.height
    
        compare_height = min(upper_h, under_h)  # 比較するピクセル数(高さ)
    
        # 上画像の高さが高い場合、差分を取得(そうでない場合は0)
        dif_h = (upper_h - under_h) if upper_h > under_h else 0
    
        for i in range(1, compare_height):
    
            search_img = upper_img.crop((0, i + dif_h, img_w, upper_h))  # 上画像のトリミング
            target_img = under_img.crop((0, 0, img_w, compare_height - i))  # 下画像のトリミング 
    
            search_np = np.array(search_img, dtype=np.uint8)  # 画像を配列へ変換(上画像)
            cv_search_img = cv2.cvtColor(search_np, cv2.COLOR_RGB2GRAY)  #グレースケール化(上画像)
    
            target_np = np.array(target_img, dtype=np.uint8)  #    〃   (下画像)
            cv_target_img = cv2.cvtColor(target_np, cv2.COLOR_RGB2GRAY)  #    〃   (下画像)
    
            res = cv2.matchTemplate(
                cv_search_img, cv_target_img, cv2.TM_CCOEFF_NORMED)  # マッチング評価(出力は類似度を表すグレースケール画像)
            res_num = cv2.minMaxLoc(res)[1]  # マッチング評価を数値で取得
            print(res_num, "\n", i)
    
            if max_res_num < res_num:  # マッチング評価結果の最大値を取得
                max_res_num = res_num
                over_pixel = target_img.height  # マッチング評価値最大時の重なりピクセル数を取得
    
        print("\n", max_res_num, "\n", over_pixel)
    
        if max_res_num > 0.98:  # 評価値が一定以上なら結合処理
            result_img = get_concat_v(upper_img.crop(
                (0, 0, img_w, upper_h - over_pixel)), under_img)  # 画像結合
            return result_img
        else:
            print("画像結合に失敗しました")
    
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    # 画像を連結させる関数(垂直方向)
    def get_concat_v(im1, im2):
        dst = Image.new('RGB', (im1.width, im1.height + im2.height))
        dst.paste(im1, (0, 0))
        dst.paste(im2, (0, im1.height))
        return dst
    
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    if __name__ == "__main__":
        upper = Image.open(r"C:\Users\aaa\Desktop\ダンボー_upper.jpg")
        under = Image.open(r"C:\Users\aaa\Desktop\ダンボー_under.jpg")
        concat_img = auto_img_concat_v(upper, under)
    
        if concat_img:
            concat_img.show()
    

    결실



    잘 결합했어.

    향후 계획


    계산량이 많고 가로가 일치하지 않는 이미지 등의 문제가 있다
    어쨌든 내가 하고 싶은 일을 했어.
    앞으로는puyautog와 조합하여 굴러다니는 화면을 자동으로 연결하는 도구를 만들고 싶습니다.

    좋은 웹페이지 즐겨찾기