--- Title: PyQt で画像のビューアを作る 8 Author: yamasyuh68 Web: https://mimemo.io/m/z2XWn4vNw84YApm --- # ベジェでトーンカーブを書く 190704 https://live.staticflickr.com/65535/48196135897_ee596c1e6a.jpg - できた ベジェはQtでpathとして描画してる そのベジェのポイントデータから look up table を作って、そのテーブルどおりにポイントを256個描画したものが緑色の点線になる 同じ軌跡です( ´∀`) Y軸の反転は気にしない~(・∀・)ノ ``` import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QPointF ,QRectF ,Qt,QPoint from PyQt5.QtGui import QPainterPath ,QPainter ,QPen from PIL import Image class App(QWidget): def __init__(self): super().__init__() self.setWindowTitle('hogetta') self.setGeometry( 500, 50 , 260 , 260 ) self.setMouseTracking (True) # <----------------***** self.LUT=[] self.plist=[] self.plist.append( QPointF(0,0) ) # start point self.plist.append( QPointF(50,50) ) #1 self.plist.append( QPointF(200,200) ) #2 self.plist.append( QPointF(255,255) ) #3 end self.a = QPointF(4,4) self.pselected = -1 # selectedpoint self.pmove = 0 # should move self.show() def mouseMoveEvent(self ,e): if self.pmove : # Dorag ing self.plist[self.pselected] = e.pos() self.update() else: # non Dorag ing self.pselected = -1 rc = QRectF ( e.pos() - self.a , e.pos() + self.a ) for i, l in enumerate( self.plist ) : if rc.contains( l ) : self.pselected = i self.update() break def mousePressEvent(self ,e): if self.pselected != -1 : self.pmove = True def mouseReleaseEvent(self ,e): self.pmove = False self.pselected = -1 self.makeLUT() self.update() self.showimg() def makeLUT(self): p1=(self.plist[0].x(),self.plist[0].y()) p2=(self.plist[1].x(),self.plist[1].y()) p3=(self.plist[2].x(),self.plist[2].y()) p4=(self.plist[3].x(),self.plist[3].y()) last_x=-1 tt=1/255 self.LUT.clear() for l in range(256): t=l*tt x = (1-t)**3*p1[0] + 3*(1-t)**2*t*p2[0] + 3*(1-t)*t**2*p3[0] + t**3*p4[0] if round(x)==last_x: continue if round(x) != last_x+1: self.LUT.append([last_x+1 , -1]) y = (1-t)**3*p1[1] + 3*(1-t)**2*t*p2[1] + 3*(1-t)*t**2*p3[1] + t**3*p4[1] last_x=round(x) self.LUT.append([ last_x , round(y)]) for l in self.LUT : if l[1] == -1 : self.LUT[l[0]][1] = int((self.LUT[l[0]-1][1] + self.LUT[l[0]+1][1])/2) def paintEvent (self,e): path = QPainterPath( self.plist[0] ) path.cubicTo( self.plist[1] , self.plist[2] , self.plist[3] ) painter= QPainter() painter.begin(self) painter.setPen( QPen( Qt.black , 2, style=Qt.SolidLine ) ) # painter.setBrush( Qt.blue ) painter.drawPath(path) # red-sub line painter.setPen( QPen( Qt.red , 2, style=Qt.DotLine ) ) painter.drawLine( self.plist[0] , self.plist[1] ) # sub painter.drawLine( self.plist[2] , self.plist[3] ) # sub if self.pselected != -1: painter.drawRect( QRectF(QPointF(self.plist[self.pselected]-self.a) , QPointF(self.plist[self.pselected]+self.a) )) painter.setPen( QPen( Qt.green , 1, style=Qt.DotLine ) ) # if self.pselected == -1: for l in self.LUT: painter.drawPoint(QPoint(l[0],l[1])) painter.end() def showimg(self): im = Image.open() rgb_im = im.convert('RGB') size = rgb_im.size im2 = Image.new('RGB',size) data = im.getdata() data2=[] width, height = im.size for l in range( width * height ): r,g,b = data[l] r = self.LUT[r][1] g = self.LUT[g][1] b = self.LUT[b][1] data2.append((r,g,b)) # <======== tupple!!!!!! im2.putdata(data2) im2.show() if __name__ == "__main__": app = QApplication(sys.argv) ex = App() sys.exit(app.exec_()) ``` # 問題~ loo up table の作成 - 画像も綺麗に補正されてるし、まあまあ上手く出来たとは思うんだけど、結構落ちる ┐('д')┌ リストのインデクスエラーで、LUTがうまく作れていないことが原因 根本は、**ベジェ曲線は与えられたx値に対するy値の計算が難しい**こと - ベジェ曲線の座標xyは0から1までのt値の関数であってxの関数ではない x値が与えられた場合、そこからtを逆算した上でyを求めるしかないが、tは一つとは限らないんだね - しかし今の課題は0から255までの整数値xに対する整数値yを求めてテーブル化すること 一般論としての解は必要ないから方法はある 近似的に作るって事ね でもそれがうまくいってない - 今のコードだと、元の直線に近いベジェならうまく作れるけど、大きく曲がるベジェだとデータに欠落が生じる **この欠落をどう埋めるかが課題、なんだと思う** --- # 与えられたベジェ曲線から関数を得る x値に基づいて3次ベジェ曲線のy値を得ることは可能ですか? - オーディオ、ベジエ、サンプリング、pcm、キュービックベジエ https://living-sun.com/ja/audio/85969-is-it-possible-to-get-the-y-value-of-a-cubic-bezier-curve-based-on-the-x-value-audio-bezier-sampling-pcm-cubic-bezier.html Pythonで最小二乗法を使って指定の点を通るベジェ曲線を近似する https://qiita.com/pashango2/items/6242b30c69524620979f ベジェ曲線 https://opentype.jp/fontguide_doc3.htm 3次元ベジェ曲線のバウンティボックスを求める https://pashango-p.hatenadiary.org/entry/20090616/1245116839 --- --> [PyQt で画像のビューアを作る もくじ](https://mimemo.io/m/QORbW4qkvOoda0N)