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)