Python tech/Computer Vision

[Python OpenCV] 이미지를 그림화 하기 (색 일반화)

콜레오네 2021. 4. 5. 08:11

OpenCV를 활용하여 이미지를 그림처럼 바꾸어주는 방법


먼저 이미지를 읽어줍니다.

import cv2
import numpy as np

image = cv2.imread("./test.jpg")

 

이미지를 Blur 처리 해주어야 합니다.

Blur 종류에는 여러가지가 있는데, 이미지에서 라인(경계선)을 살리기 위해 bilateralFilter 방식을 적용합니다.

함수를 만들어 주겠습니다.

def blurring( image, radius = 10, sigmaColor = 50 ) :
    qimg = image.copy() #이미지 복사
    
    # 이미지 크기에 따라 blur 효과의 정도를 달리합니다.
    sigmaColor += (qimg.shape[1] * qimg.shape[0]) // 100000
    radius += (qimg.shape[1] * qimg.shape[0]) // 100000
    
    blurring = cv2.bilateralFilter(qimg,  radius, sigmaColor, 70)
        
    return blurring
    

radius : 블러링 계산에 사용될 이웃한 픽셀의 크기

sigmaColor : Color 공간에서 Sigma 공간의 크기, 높아질수록 블러링 효과가 커짐


테스트 파일 원본

원본 이미지

 

블러 처리한 결과

블러 처리한 이미지


블러 처리로는 그림이라고 보기에는 조금 어렵네요.

주변의 비슷한 색끼리 묶어주면 어떨까요??

def createSimilarColorMap(img, value = 15):
        image = img.copy() #이미지 복사
        map = [] # 결과 이미지 변수
        for y, row in enumerate(image): # y 좌표
            line = [] 
            for x, bgr in enumerate(row): # x 좌표
                colorChange = False # 색 변경 여부
                blue, green, red = bgr # 해당 좌표의 색 추출
                for c in [-1, 1]: # 상하좌우 비교
                    try:  # indexError 방지를 위해 예외 처리 구문 삽입
                        b, g, r = image[y, x+c] # x 축 좌우 색 추출
                        # 같은 색이면 pass
                        if b==blue and g==green and r==red: pass 
                        # 색이 -value < color < +value 사이 값이면 색 변경
                        elif  b-value< blue <b+value and \
                        g-value< green <g+value and \
                        r-value< red <r+value:
                            line.append( [b, g, r] )
                            image[y][x] = [ b, g, r ]
                            colorChange = True
                            break
                    except IndexError as e: pass
                    
                    try: 
                        b, g, r = image[y+c, x] # y 축 상하 색 추출
                        if b==blue and g==green and r==red: pass
                        elif  b-value< blue <b+value and \
                        g-value< green <g+value and \
                        r-value< red <r+value: 
                            line.append( [b, g, r] )
                            image[y][x] = [ b, g, r ]
                            colorChange = True
                            break
                    except IndexError as e: pass
                # 만약 색 변경이 없다면, 기존 색 입력
                if not colorChange: line.append( [blue, green, red] )
                
            map.append( line )
        # numpy nd.array 형태로 반환
        return np.array(map)

위 함수를 적용하면 조금 더 그림과 같은 형태가 만들어집니다.

 

다만, value 값을 너무 작게 주면 변화가 거의 없고

value 값을 너무 크게 주면 형태가 너무 깨지게 됩니다.

 

이미지 혹은 상황에 맞게 적절한 값을 넣어주면 될 것 같습니다.

경험상 10~20 사이 값이면 적당한 것으로 보여집니다.


비슷한 색 병합 결과

주변 비슷한 색 병합

 

이제 어느 정도 그림처럼 보여지네요.

라인도 조금 더 뚜렿해진 것으로 보입니다.

 


다른 예시 추가

확대해서 보시면 됩니다...^^

원본 이미지, 블러 이미지, 주변 색 병합 이미지

 

21.05.16 업데이트 !!!

이후 cv2.kmeans() 를 활용하여 성능을 높였습니다.

해당 포스팅에서 적용한 알고리즘보다 시간도 덜 걸리고, 효율도 좋으니

다음 포스팅을 참고하시기 바랍니다..

https://tech-diary.tistory.com/25

 

[Python opencv] K-means 활용, 이미지 색상 개수 줄이기

Using cv2.kmeans, reduce number of color on image 지난번 "이미지 그림화" 포스팅에 더 개선된 알고리즘을 적용합니다. 실행 시간도 단축되었고, 그림화 및 색상 단순화 효과도 성능이 개선되었습니다. 지난

tech-diary.tistory.com

 

 

반응형