Do auto level without photoshop -> 속도 개선 성공 :)

suapapa의 이미지

안녕하세요. 첫 글을 올리는 오랜 눈팅회원 수아아빠입니다.
왠일인지 파이썬 사용자 모임(http://python.or.kr)이 막혀 있네요.
파이썬으로 작성한 Auto Level 프로그램에 대해 도움을 얻고자 합니다.

똑딱이(후지 F440)를 자주 사용하는 편인데,
워낙 카메라에 잼병이고 관심도 없다보니 사진 영 메롱입니다.
포토샵의 Auto Level로 후보정된 정도면 좋겠는데,
여러장의 사진을 다 포토샵으로 보정하기가 너무 귀찮아서..

구글링 결과 아래의 링크에서 힌트를 얻었습니다. :)
http://mail.python.org/pipermail/image-sig/2005-September/003515.html
링크의 내용을 요약해 보면..

  1. 이미지 히스토리그램상 출현빈도가 적은 양 끝을 제거
  2. 가운데 부분을 다시 0~255에 맞게 늘림
  3. 흐리멍텅한 사진이 깔끔하게 보정됨

어느정도 양 끝을 잘라야 되는지를 알지 못해 포토샵으로 보정된 사진과 비교하여 시험해 본 결과,
사진의 1%를 threshold로 잡았습니다. ( -> 0.5%로 수정합니다.)

댓글중에 힌트를 얻어
포토샵 도움말을 참조해 보니 0.5%가 기본값이고 0.5%~1.0%를 권장하고 있었습니다.
삽질이 무색해 지는 순간입니다. T-T;

포토샵 AutoLevel과 정확히 일치하지는 않지만 만족스러운 결과가 나오게 되었습니다. :)

하지만 사진이 큰 경우(2304*1728) 30초 정도의 시간이 걸리네요 T-T
문제는 소스의 "아 여기 너무 느려요 T-T" 부분입니다.

저 부분을 개선할 여지가 있을까요? -> 개선된 소스 본문 밑에 추가되었습니다.

소스 전체는 아래와 같습니다.

import Image
 
def getMinMax(histo,threshHold = 0):
    minV = 0
    maxV = 0
    for i in range(0,256):
        if sum(histo[:i+1]) > threshHold:
            minV = i
            break
    for i in range(255,0,-1):
        if sum(histo[i:]) > threshHold:
            maxV = i
            break
    print 'minV, maxV :', minV, maxV
    return minV, maxV
 
def getAutoLevel(minV, maxV, data):
    result = ((data-minV)*255)/(maxV-minV)
    return result #return int(round(result))
 
def autoLevel(imgName, outName = None, threshold = 0):
    if not outName:
        outName = imgName
 
    img = Image.open(imgName)
    data = img.getdata()
 
    ## Set threshold ##
    if threshold == 0: #auto threshold "0.5%"
        threshold = (len(data)*0.5)/100
        print 'auto threshold %d'%threshold
 
    ## Find cutting point ##
    histo = img.histogram()
    minR,maxR = getMinMax(histo[:256],threshold)
    minG,maxG = getMinMax(histo[256:256*2],threshold)
    minB,maxB = getMinMax(histo[256*2:],threshold)
 
    ## Create new image ##
    #print outName, 
    imgNew = Image.new('RGB',img.size)   
    width = img.size[0]
    x = 0
    y = 0
    for i in range(len(data)):  # <- 아 여기 너무 느려요 T-T
        r,g,b = data[i]
        r = getAutoLevel(minR, maxR, r)
        g = getAutoLevel(minG, maxG, g)
        b = getAutoLevel(minB, maxB, b)
        imgNew.putpixel((x,y),(r,g,b))
        x += 1
        if x >= width:
            x = 0
            y+=1
    #print len(data)
    imgNew.save(outName)
    return
 
def __test_1():
    import glob
    import os
    import time
    dirName = r'D:\Image\'
    for f in glob.glob(os.path.join(dirName,'*.jpg')):
        print f
        if not os.path.isfile(f):
            print '##',
            print f
            continue	
        s = time.time()
        autoLevel(f)
        e = time.time()
        print 'it takes %d secs\n'%int(e-s)
 
 
# test function #
if __name__ == '__main__':
    __test_1()

--- 여기부터 추가 내용입니다. ----

도움주신 글들을 보고, PIL 메뉴얼을 정독한후, 행렬 계산을 기억해 내느라 진땀을 뺀후.. ㅎㅎ
속도 개선을 이루었습니다. 아싸!

아래는 개선된 코드 일부입니다.

def autoLevel(imgName, outName = None, threshold = 0):
    if not outName:
        outName = imgName
 
    img = Image.open(imgName)
    data = img.getdata()
 
    ## Set threshold ##
    if threshold == 0: #auto threshold "1%"
        threshold = (len(data)*0.5)/100
        print 'auto threshold %d'%threshold
 
    ## Find cutting point ##
    histo = img.histogram()
    minR,maxR = getMinMax(histo[:256],threshold)
    minG,maxG = getMinMax(histo[256:256*2],threshold)
    minB,maxB = getMinMax(histo[256*2:],threshold)
 
    ## Create new image ##
    rgb2al_rgb = (
        (255.0/(maxR-minR)), 0.0, 0.0, -((255.0*minR)/(maxR-minR)),
        0.0, (255.0/(maxG-minG)), 0.0, -((255.0*minG)/(maxG-minG)),
        0.0, 0.0, (255.0/(maxB-minB)), -((255.0*minB)/(maxB-minB)) )
    imgNew = img.convert("RGB", rgb2al_rgb)
    imgNew.save(outName)
    return

매 픽셀을 putpixel로 찍어주는게 시간을 많이 잡아 먹더군요!
저렇게 convert함수를 사용한 결과

30초 걸리던 작업이 1초로 드라마틱하게 단축되었습니다.
이제 포토샵 빠이빠이~

관심 가져주신 모든 분들 감사드립니다.

File attachments: 
첨부파일 크기
Image icon sample.png291.28 KB
hey의 이미지

루프 안에서 data 배열의 크기가 안 바뀌는 것 같은데, 루프 밖에서 해줄 수 있지 않을까요?

May the F/OSS be with you..



----------------------------
May the F/OSS be with you..


suapapa의 이미지

data의 내용(img의 각 픽셀 rgb값)에 autolevel을 적용해서 imgNew에 찍어주게 되어있는데요..
data의 내용을 미리 가공하려면 len(data)만큼 루프를 두번(가공할때 한번, 찍어줄때 한번) 돌게 되서 더 느려지네요. 아 지끈 -"-;

좀더 힌트를 부탁드립니다. T-T

ironiris의 이미지

웹에 올리는 용도로 일괄 변환, 오토레벨,리사이즈정도만 하실거면 포토웍스라고 국산 공개 프로그램이 와땁니다.

suapapa의 이미지

좋은 프로그램 소개 감사드립니다. 아래의 링크네요.
http://andojung.com/photoWORKS/

포토웍스 홈페이지의 게시판을 검색해본 결과..
threshold를 계산하는 방법을 찾게 되었습니다.

바로 다름아닌 포토샵 도움말에 있네요 -_-;;
threshold값을 0.5%로 변경해 봐야 겠습니다.

송효진의 이미지

라이센스 문제가 아니시면 포토샵도 일괄 되요.:)
이름이 뭐더라...
오른쪽 툴박스에 녹화버튼 있고,
파일메뉴 중간쯤에 보면 auto 어쩌고가 있습니다.
그걸로 설명 한번 찾아보세요.
다양한 옵션을 한번에 다 적용할 수도 있어서 편리합니다.

emerge money

suapapa의 이미지

포토샵에 매크로 기능이 있었네요.
하지만 어떻게 사용하는지 배우기가 귀찮고, 제가 짜 논게 아까워서,
사용하지는 않을 것 같습니다. :)

bus710의 이미지

그러나 저러나.... python.or.kr 은 왜 안열릴까요?...ㅠ.ㅠ

life is only one time

suapapa의 이미지

다시 열리네요..
하지만 제 아이디는 정지 상태네요 T-T;
여기저기 눈팅회원의 비애..

아빠곰의 이미지

이런 훌륭한 프로그램은, 프로그램Q&A에 있어야 후학들이 보고 배울텐데... :)

나중에 해보려고 살짝 찾아보면, 어디있는지 모르겠더라고요;;
----
아발발다빠따반반나다발딸발발다빠따따맣밤밤따받따발발다따밝다발발다빠따따밤반다빠따다맣밥발
발다따밥다발발다따박다발발다빠따따밞밭밭다따다맣아희

----
아발발다빠따반반나다발딸발발다빠따따맣밤밤따받따발발다따밝다발발다빠따따밤반다빠따다맣밥발
발다따밥다발발다따박다발발다빠따따밞밭밭다따다맣아희

suapapa의 이미지

장난가분께서 답글을 달아주셨네요.
장난위키쪽에서도 오랜 눈팅회원입니다. :)

칭찬 감사드립니다. 하지만..
파이썬이 훌륭한 프로그램이고, 이건 그냥 장난이죠 :)

눈팅회원만 하다 보니 어디에 글을 올리는게 맞는지 개념이 없어서 대충 올려 버리고 말았네요
옮길수는 없나요? -> 옮겼습니다. 쉽게 찾을 수 있네요. :)

dormael의 이미지

더 진행 안되는건가요? ^^
파이썬은 모르지만 재미있을것 같은데 아쉽네용.

-- Signature --
青い空大好き。
蒼井ソラもっと好き。
파란 하늘 너무 좋아.
아오이 소라 더좋아.

suapapa의 이미지

-그 재밌는- 파이썬을 좀 알아 보신다면 위의 소스로 다 진행(자체실행및 모듈화까지) 된 상태라는 걸 아실 수 있으실 겁니다.

느리다는거 빼고요 :P

atie의 이미지

약간 옆길로... 그 메일 이후를 읽다보니 GIMP Batch Mode에 대한 것도 나오는군요. 거기의 스크립트를 쓸 경우 위의 python 코드와 비교해서 결과 이미지의 품질과 실행 속도에 대해 알 수 있을까요?
----
I paint objects as I think them, not as I see them.
Ubuntu Dapper user / Ubuntu KoreanTeam

----
I paint objects as I think them, not as I see them.
atie's minipage

suapapa의 이미지

조금 살펴보다가..
김프의 매크로가 익숙치 않아 배우길 포기하였습니다. T-T

이참에 윈도용 김프를 깔아봤는데 예전(1년전)에 써봤을때와 확연히 달라졌네요.
예쁘고 쓸만하게 바뀌었습니다.

하지만.. 왜 김프의 Curve에는 Auto버튼이 없는 걸까요? 툴툴

7339989b62a014c4ce6e31b3540bc7b5f06455024f22753f6235c935e8e5의 이미지

    for r, g, b in data:  # 느리다고 표시하신 부분
        #r,g,b = data[i] #주석 처리
        ...

range로 리스트를 일일히 생성하는 작업 때문에 느릴지도 모르겠군요. 위처럼 고쳐보세요~ 별 차이는 없을 것 같지만 =3
suapapa의 이미지

이런 저는 그 루프전체에서 속도가 느려진다는 의미었는데..
제가 의미전달을 잘못했네요 ㄲㄲ

알려주신 방법으로 불행히도 속도 개선은 미비했지만 (1초 가량 개선됨)
보다 파이썬스럽게 코딩하는 방법을 배워갑니다.

감사합니다 :)

thyoo의 이미지

scipy (numpy)를 고려해 보세요.

http://www.scipy.org/
___________________________________
Less is More (Robert Browning)

___________________________________
Less is More (Robert Browning)

suapapa의 이미지

scipy를 어디다 쓰면 좋을까요 -_-?

hey의 이미지

잘됐습니다. :]
저도 루프 부분이 느리다는 얘기를 잘못 읽었었군요.

May the F/OSS be with you..



----------------------------
May the F/OSS be with you..


suapapa의 이미지

저를 제외하곤 다들 그 줄이 느리다고 이해하시네요. -_-;

익명사용자의 이미지

range() 안의 인자가 클경우에는 xrange가 더 좋다고 그러던데요..

suapapa의 이미지

참고하고 추후 range를 쓸때 고려해 보겠습니다.

wkpark의 이미지

코드놀이터에 들어갈만한 재밌는 글인것 같습니다~ 분류태그로 코드놀이터도 붙여주시길~

온갖 참된 삶은 만남이다 --Martin Buber

suapapa의 이미지

더불어 wkpark님의 게시물도 재밌게 읽어보았습니다. :)

7339989b62a014c4ce6e31b3540bc7b5f06455024f22753f6235c935e8e5의 이미지

psyco를 한번 붙여보세요. 파이썬용 JIT입니다.
http://psyco.sourceforge.net/

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.