PyQt で画像のビューアを作る 8 version 10
:追加された部分
:削除された部分
(差分が大きい場合、文字単位では表示しません)
ベジェでトーンカーブを書く
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(r"e:\Programs\python\qt\pil\image.jpg")
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を求めてテーブル化すること
一般論としての解は必要ないから方法はある
近似的に作るって事ね
でもそれがうまくいってない
- 今のコードだと、元の直線に近いベジェならうまく作れるけど、大きく曲がるベジェだとデータに欠落が生じる
**この欠落をどう埋めるかが課題、なんだと思う**
---
--> [PyQt で画像のビューアを作る 目次](https://mimemo.io/m/QORbW4qkvOoda0N)
- できた
ベジェは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(r"e:\Programs\python\qt\pil\image.jpg")
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を求めてテーブル化すること
一般論としての解は必要ないから方法はある
近似的に作るって事ね
でもそれがうまくいってない - 今のコードだと、元の直線に近いベジェならうまく作れるけど、大きく曲がるベジェだとデータに欠落が生じる
この欠落をどう埋めるかが課題、なんだと思う