본문 바로가기

졸업프로젝트/OpenCV

[openCV]답지 문제별로 자르기(3)

728x90

 

페이지가 분리되어 쪼개진 하나의 답을 하나의 이미지로 합치기 

 

2page 왼쪽 페이지 8번

(중략)

2p 오른쪽 페이지 15번(1)

 

3p 왼쪽 페이지 15번(2)

위의 사진 2개와 같은 사진을 하나로 합쳐야한다 

 

아이디어) 

이미지를 차례대로 받아오면서, 

"답"이미지가 존재하는 경우 이미지를 그냥 저장

"답"이미지가 존재하지 않는 경우 배열에 이미지를 저장해두고,

그 이후로 최초의 "답"이미지를 보유한 사진이 나오면

배열에 저장해둔 사진을 차례대로 꺼내 이어서 저장해준다 

 

이를 위해  flag를 이용한다.

"답"이미지를 찾아서 이미지를 저장한 경우는 flag = 1

"답"이미지가 없는 이미지를 만나 배열에 저장하는 경우는 flag = 0 

 

 

사용할 변수 초기화

        qnum=1
        flag = 1
        noans_count=0
        image_arr = [None]*8

qnum : 저장할 이미지에 부여할 고유번호

flag : 위쪽 참고

noans_count : 이미지 경로를 저장해둘 배열의 index로 사용할 변수 , 0으로 초기화

imag_arr : 이미지 경로를 저장할 배열

 

파이썬에서 리스트의 크기를 설정하고 초기화하는 방법은 다음과 같다

list = [None] * (list의 길이)

 

 

 

이미지 내에 "답"이미지가 있는지 확인하기 

#이미지 합치기
def combine_image(image_url):
    global flag
    global image_arr
    global noans_count


    image = cv2.imread(image_url)
    imgray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 

    template = cv2.imread('/gdrive/MyDrive/ProjectStudy/answer_temp.png',0)

    res = cv2.matchTemplate(imgray, template, cv2.TM_CCOEFF_NORMED)
    threshold = .55
    loc = np.where(res >= threshold)

    length = len(loc[0])

먼저 이전 게시글에서 한 방법과 동일하게 matchTemplate를 이용하여 

해당 이미지 내에 "답"이미지가 있는지 검사한다 

 

이미지 내에 "답"이미지가 있는지 검사하는 방법은 loc[0]또는 loc[1]의 길이를 출력해보는 것이다.

* len(loc)는 array[(x좌표의 배열)], array[(y좌표의 배열)] <- x좌표/y좌표 라서 무조건 다 2임 
중요한건 어레이가 비어있는지 이라서 
loc[0] / loc[1] 이렇게 해야 비어있는건지 아닌지 알 수 있음

 

"답"이라는 이미지가 없는 경우 

    #"답"이미지가 없는 이미지의 경우 
    if (length <= 0):
    #이미지의 경로를 image_arr배열에 저장
        image_arr[noans_count] = image_url
        #배열 index를 증가시킴 
        noans_count=noans_count+1
        #flag를 0으로 설정
        flag = 0

image_arr이라는 배열의 현재 index(noans_count)에 이미지의 경로를 저장한다

(그냥 이미지를 저장하는 방법에서 오류가 났기 때문에 string인 경로를 저장하는 방법을 사용했다)

저장했으면, 

(매우 긴 해설의 경우 여러 이미지를 합쳐야 할 수 있으므로) index를 하나 증가시킨다.

그런 뒤 flag를 0으로 설정한다

 

 

이미지 합치기 

flag가 0이어서 배열에 이미지 경로가 1개 이상 저장되어 있는데, 

"답"이미지를 가진 이미지( 이어 붙일 이미지의 마지막 부분)가 입력된 경우 

    #배열에 이미지 경로가 저장되어 있고(flag = 0 ) "답"이미지를 가진 이미지를 찾은 경우
    elif (length >0 and flag ==0):
        #여태까지 배열에 저장된 모든 이미지를 이어줌 
        for i in range(noans_count-1,-1,-1):
            image_noans = cv2.imread(image_arr[i])
            image = cv2.vconcat([image_noans,image])
            noans_count = noans_count-1

        #이어서 하나로 만든 이미지를 저장 
        include(image,qnum)
        #배열 index를 0으로 초기화 
        if (noans_count < 0):
            noans_count = 0
        #flag를 1으로 설정 
        flag = 1

 

배열에 저장해둔 이미지 경로로 cv2.imread를 이용해 이미지를 읽어온다.

for i in range(noans_count-1, -1, -1)

range(시작 수 , 끝수 -1 , 간격) 

noans_count - 1 부터 0까지 1씩 감소( -1씩 증가 ) 

 

noans_count는 image_arr의 마지막 index인데, 채울 때 마다 +1을 했기 때문에

아직 채워지지 않은 칸에 있기 때문에 -1을 해주어야한다.

0부터 채웠기 때문에 0까지 해주어야 하며, 1씩 감소시켜서 사용해야한다.

 

vconcat([위쪽 이미지, 아래쪽 이미지])

cv2.vconcat([image_noans,image])

이미지를 세로 방향으로 합쳐주는 함수로, 앞쪽에 쓴 이미지가 위쪽으로 뒤쪽에 쓴 이미지가 아래쪽으로 간다.

index가 줄어들 수록 위쪽에 존재해야 하는 이미지 이므로 image_noans에 저장해 둔 이미지를 앞쪽에 써주어야 한다.

 

for문을 index 0까지 돈 경우 

배열에 저장되었던 이미지가 전부 사용되었으므로

index를 초기화해주고, 합친 이미지를 저장해준다.

 

이미지를 저장했으므로 flag를 1로 변경해준다. 

 

 

이미 온전한 이미지 

    #이미지가 온전한 (문제번호~"답"이미지까지 존재하는) 이미지인 경우
    else:
        #이미지를 저장 
        include(image,qnum) 
        flag=1   

이미 처음부터 온전한 이미지의 경우 그냥 저장해 준 뒤 

flag를 1로 설정해준다.

 

함수 전체

#이미지 합치기
def combine_image(image_url):
    global flag
    global image_arr
    global noans_count


    image = cv2.imread(image_url)
    imgray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 

    template = cv2.imread('/gdrive/MyDrive/ProjectStudy/answer_temp.png',0)

    res = cv2.matchTemplate(imgray, template, cv2.TM_CCOEFF_NORMED)
    threshold = .55
    loc = np.where(res >= threshold)

    length = len(loc[0])

    #"답"이미지가 없는 이미지의 경우 
    if (length <= 0):
    #이미지의 경로를 image_arr배열에 저장
        image_arr[noans_count] = image_url
        #배열 index를 증가시킴 
        noans_count=noans_count+1
        #flag를 0으로 설정
        flag = 0
        
    #배열에 이미지 경로가 저장되어 있고(flag = 0 ) "답"이미지를 가진 이미지를 찾은 경우
    elif (length >0 and flag ==0):
        #여태까지 배열에 저장된 모든 이미지를 이어줌 
        for i in range(noans_count-1,-1,-1):
            image_noans = cv2.imread(image_arr[i])
            image = cv2.vconcat([image_noans,image])
            noans_count = noans_count-1

        #이어서 하나로 만든 이미지를 저장 
        include(image,qnum)
        #배열 index를 0으로 초기화 
        if (noans_count < 0):
            noans_count = 0
        #flag를 1으로 설정 
        flag = 1
    #이미지가 온전한 (문제번호~"답"이미지까지 존재하는) 이미지인 경우
    else:
        #이미지를 저장 
        include(image,qnum) 
        flag=1   

 

 

특정 경로에서 이미지를 순서대로 불러와서(sort()함수 사용)

combine_image함수에 적용시키면 다음과 같은 결과를 얻을 수 있다

 

결과)

15번이 합쳐진 모습

(나머지는 생략)

 

물론 이 방법으로 할 경우 

이미 잘라진 이미지에 빠진이미지나 중복이미지 등 이상한 이미지가 있으면안된다 

 

 

 

전체코드)

! apt install tesseract-ocr
! apt install libtesseract-dev
! pip install Pillow
! pip install pytesseract
! sudo apt-get install tesseract-ocr-script-hang tesseract-ocr-script-hang-vert


#라이브러리 임포트
import numpy as np
import cv2 #openCV package
from google.colab.patches import cv2_imshow
import re
import pytesseract
import glob
import os
import time
from PIL import ImageEnhance, ImageFilter, Image
from matplotlib import pyplot as plt


#구글 드라이브와 연동 
from google.colab import drive
drive.mount('/gdrive')


#이미지 저장 함수 
def include(cropped,num):

    global qnum
    number = str(num)
    
    #식별번호를 4자리로 맞추기 위해 
    if (len(number)==1):
        number = '000'+str(num)
    elif (len(number)==2):
        number = '00'+str(num)
    else:
        number = '0'+str(num)

#파일이름 
    newfile=save_path+str(num)+"_pg"+j+".png"
    print(newfile)
#파일저장
    cv2.imwrite(newfile,cropped)
#고유번호 1 증가 
    qnum=qnum+1
    

#경로 자동 생성 함수 
def make_path_SW():

    book_list=['2021','2020','2019','2018','2017']
    for i in range(len(book_list)):
        path=book_list[i]+'/'
        path_list.append(path)



#이미지 합치기
def combine_image(image_url):
    global flag
    global image_arr
    global noans_count


    image = cv2.imread(image_url)
    imgray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 

    template = cv2.imread('/gdrive/MyDrive/ProjectStudy/answer_temp.png',0)

    res = cv2.matchTemplate(imgray, template, cv2.TM_CCOEFF_NORMED)
    threshold = .55
    loc = np.where(res >= threshold)

    length = len(loc[0])

    #"답"이미지가 없는 이미지의 경우 
    if (length <= 0):
    #이미지의 경로를 image_arr배열에 저장
        image_arr[noans_count] = image_url
        #배열 index를 증가시킴 
        noans_count=noans_count+1
        #flag를 0으로 설정
        flag = 0
        
    #배열에 이미지 경로가 저장되어 있고(flag = 0 ) "답"이미지를 가진 이미지를 찾은 경우
    elif (length >0 and flag ==0):
        #여태까지 배열에 저장된 모든 이미지를 이어줌 
        for i in range(noans_count-1,-1,-1):
            image_noans = cv2.imread(image_arr[i])
            image = cv2.vconcat([image_noans,image])
            noans_count = noans_count-1

        #이어서 하나로 만든 이미지를 저장 
        include(image,qnum)
        #배열 index를 0으로 초기화 
        if (noans_count < 0):
            noans_count = 0
        #flag를 1으로 설정 
        flag = 1
    #이미지가 온전한 (문제번호~"답"이미지까지 존재하는) 이미지인 경우
    else:
        #이미지를 저장 
        include(image,qnum) 
        flag=1   




#함수실행 
if __name__ == "__main__":
    path_list=[]
    make_path_SW()
    path_prev='/gdrive/MyDrive/ProjectStudy/answers/'
    path_back='/Suwan_na/'

    for i in range(len(path_list)):
        qnum=1
        flag = 1
        noans_count=0
        image_arr = [None]*8

        load_path=path_prev+'revised_cropped'+path_back+path_list[i]
        save_path=path_prev+'cropped_final'+path_back+path_list[i]
        os.chdir(load_path)
    
        images=glob.glob('./*.png')
        
        #폴더내 이미지 순서대로 불러오기
        images.sort()
        #print(images)
       
        for i in range(len(images)):
            filename=images[i]
            page_num=filename[-7:-4]
            
            page_url = load_path+images[i]
            j=page_num
            combine_image(page_url)

 

 

 

참고사이트)

파이썬 리스트의 선언 및 초기화 (tistory.com)

 

파이썬 리스트의 선언 및 초기화

파이썬에서 리스트를 사용할 경우에, 초기화를 하지 않고, 배열에 대입하면 `list out of index` 에러가 뜨게 됩니다. 이러한 경우에 리스트의 크기를 설정하고 초기화 하는 방법은 다음과 같습니다,

coffeedjason.tistory.com

 

728x90