0 PyQt で画像のビューアを作る 7

  • pillow の明るさが嫌なのでトーンカーブのことを調べだした

190702

ベジェ曲線をグリグリしてみた

  • マスクでenhanceは出来たんだけど肝心のpillowのenhanceが不満で、いろいろ調べてるうちにトーンカーブでピクセルを補正していくしかないような気がしてきた
  • で、まずはマウスでグリグリ曲線を描くにはどうしたら良いのだろうと思い、Qtでベジェを書く実験をしたら結構簡単にできた
    でもこの曲線を数学の関数として扱って、与えられたxに対してYを返さなければいけないがやり方がわかんない┐('д')┌
    調べればわかるんだろうけど、そもそもベジェを書くことが目的では無いことに気づいた( ´∀`)
    まあ楽しかったしこれでパスオブジェクトを作れるようになったのでどこかでまたやろう
  • トーンカーブの実装には多分別のアプローチが必要
    右上がりの直線を書いて、そこにポイントを追加してなめらかな曲線にする、これは多分スプライン補間って分野だ
    python ってそういう数学的なものは得意らしい
    scipy ってのを早速インストしてみたので調べてやってみよう

190704

トーンカーブの実装

  • 右上がりの直線を描いてマウスで上に持ち上げたら線が上に膨らんで画像も明るくなるって感じ
    トーンカーブですね、とりあえず出来た(・∀・)ノ
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QPointF , QPoint ,QRectF ,Qt
from PyQt5.QtGui import QPainterPath ,QPainter ,QPen
from scipy import interpolate

from PIL import Image
import numpy

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle('hogetta')
        self.setGeometry( 500, 50 , 500 , 500 )
        self.x=[0,170,255]  # to use scipy function
        self.y=[255,170,0]
        self.f_list=[]      # look up table ( curve )
        for l in range(256):
            self.f_list.append(QPoint( l , 255-l))   # make initial table --> line
        self.a = QPoint(4,4) # Tolerance in detecting point
        self.pselected = -1             # selectedpoint
        self.pmove = 0                  # move flag
        self.show()

    def mouseMoveEvent(self ,e):
        if self.pmove :  # Dorag ing
            self.x[1] = e.pos().x()
            self.y[1] = e.pos().y()
            self.makeLUT()
            self.update()

    def mousePressEvent(self ,e):
        self.pmove = True
    def mouseReleaseEvent(self ,e):
        self.pmove = False
        self.showimg()

    def makeLUT(self): # make look up table by function
        # linear quadratic × cubic
        func = interpolate.interp1d(self.x, self.y, kind="quadratic" ) 
        for l in range(256):
            value=int(func(l))
            value = value if value >=0 else 0 
            self.f_list[l] = QPoint( l , value )

    def paintEvent (self,e):
        painter= QPainter()
        painter.begin(self) 
        painter.setPen( QPen( Qt.black , 2, style=Qt.SolidLine ) )
        for l in range( 255 ):
            painter.drawPoint( self.f_list[l] )
        painter.setPen( QPen( Qt.red , 8, style=Qt.SolidLine ) )
        painter.drawPoint( self.x[1] ,  self.y[1] )
        painter.end() 

    def showimg(self):
        im = Image.open(<pass>)
        rgb_im = im.convert('RGB')
        size = rgb_im.size
        im2 = Image.new('RGBA',size)

        data = im.getdata()
        data2=[]
        width, height = im.size
        for l in range( width * height ):
            r,g,b = data[l]
            r = 255-self.f_list[r].y()  # <<===
            g = 255-self.f_list[g].y()  # <<===
            b = 255-self.f_list[b].y()  # <<===
            data2.append((r,g,b,0))   #  <======== tupple!!!!!!
        im2.putdata(data2)
        im2.show()
        return

        # getpixel 遅い
        for x in range(size[0]):
            for y in range(size[1]):
                r,g,b = rgb_im.getpixel((x,y))
                # print(r,g,b)
                r = int(self.f_list[r].y())
                g = int(self.f_list[g].y())
                b = int(self.f_list[b].y())

                im2.putpixel((x,y),(r,g,b,0))

        im2.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

  • 上下がおかしいかも( ̄― ̄?)
    描画ってY軸が逆になるからやりづらいのよ

スプライン補間した関数を取得

  • scipy君に頼んで何とか出来たが、よくみる
    interpolate.interp1d(x, y, kind="cubic" )
    これだとエラーになる
    cubic の場合、与えるxがある程度均等に並んでる必要があるみたいだ
    トーンカーブは始点と終点は固定で、中間の任意の点を上げ下げする
    こうした三点を与えても計算出来ないんだと思う
  • でドキュメントを読んで kind パラメータを順に試したら、
    interpolate.interp1d(x, y, kind="quadratic" )
    これでイケました
    試行錯誤なので理屈はわかってませんが( ´∀`)
  • この関数さえ出来ればLUTを作るのは単純作業で簡単
  • LUTを元にドットを描画するように曲線を描くことに成功

画像に適用

  • で、LUTを元にpillowでピクセルを補正して表示することに成功
  • これは簡単だったんだけど、getpixcelだと遅くて使えない┐('д')┌
  • せっかくscipyをインストしたのでそれについてきたNumpyでやってみたが、arrayを一括で上げようとしてもうまくいかない
    このサイト ↓ の情報だと、Numpyよりもpillowのgetdataが速いって事だったので試したら何とかイケた
    https://kuranabe.hatenablog.com/entry/2018/08/18/234355
  • getdata はピクセルデータを縦*横の数の一列のリストで取得できる
    単純に全てのデータをLUTによって変換して新しいデータを作って、もとのpillowにputdata()で戻してやればOK
    ちなみにこのデータはリストだけどそれぞれの要素はタプルで返すことに注意
0

メモを他の人に見せる

このメモを見せたい人に、このURL(今開いているページのURLです)を教えてあげてください

コメント(0)

  • someone

  • someone