PyQt で画像のビューアを作る 8 version 12

2019/07/05 09:27 by yamasyuh68
  :追加された部分   :削除された部分
(差分が大きい場合、文字単位では表示しません)
PyQt で画像のビューアを作る 8
# ベジェでトーンカーブを書く

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(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)      

ベジェでトーンカーブを書く

190704

  • できた
    ベジェは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 で画像のビューアを作る 目次