[ todo ] PyQt で画像のビューアを作る version 27

2019/06/25 16:10 by yamasyuh68
  :追加された部分   :削除された部分
(差分が大きい場合、文字単位では表示しません)
todo PyQt で画像のビューアを作る
@[TOC](項目)

--------------
# 画像変換 まず実験

マスク画像を重ねる
https://note.nkmk.me/python-pillow-paste/


①デザイナでテスト用のボタン作っておこう
②同じサイズ、8bitグレイスケールのグラデ画像を作っておく

orig=Image.open(< pass >)
grad=Image.open(< pass >)

orig_back=orig.copy()
orig_conv=origk.********

orig_conv_masked = orig_back.paste(orig_conv, (0,0), grad )

     orig_conv_masked   を表示してみる


### こんな感じでどうでしょう

```
fname=r''

with open( fname , 'rb' ) as f :
 data=f.read( 20 )

key=b'\ff\fe'
offset=0
for i in range(len( data )-5):
 if data[i:i+2] == key :
  offset=i
  break

if not offset :
 print('can't find')
 quit()

length = data[offset+3]*256 + data[offset+4]  # ここ逆かも

with open( fname , 'rb' ) as f :
 f.seek(offset+4)
 data=f.read( length )

data.append( b'\00' )

print( data.encode() )

```


# Exif関係

- ファイル~読み取ったバイナリをbiとして、biはリストなはずだからこんなことで

```
bi = b'\x00\x01\x02\xff\xfe\x05\x06\x07' 
key = b'\xff\xfe'

for i in range(len(bi)-1):
 if bi[i:i+2] == key :
  print('hit' , i , bi[i+2:i+4])
  break
```
- key のバイナリを検索してヒットしたら次のニバイトを取り出す
これがサイズでそのに文字列がサイズ分入ってる
pythonのスライスはいいわ!!

- サイズが10として、① 0a 00 ② 00 0a どっちで書かれてるか?
いずれにしてもそれぞれを数値に戻してから、どっちかに256を掛けて足せば良い

```
key1 = b'\x00\x0a'
key2 = b'\x0a\x00'

print( int.from_bytes(key1, 'big') )    ---> 10
print( int.from_bytes(key1, 'little') ) ---> 2560
print( int.from_bytes(key2, 'big') )---> 2560
print( int.from_bytes(key2, 'little') ) --->10

# これでいいか?
print( key1[0]*256 + key1[1] )
print( key1[1]*256 + key1[0] )
```
**後は指定位置から指定バイトを読むだけだ~(^_^)**




# ペンの色を指定

```
23.    painter.setPen(Qt.red)
24.    #painter.setPen(QColor(255, 0, 0))
26.    # 使用するフォントを指定
27.    painter.setFont(QFont('Times', 30))
28.    # テキスト描画
29.    painter.drawText(image.rect(), Qt.AlignCenter, 'Symfoware')
30.    # 画像の編集終了
31.    painter.end()
```

----
- コンテキストメニューを作るか
結構長くなるから別ファイルにしておくか??
このソフトの機能を呼び出すときの主要な手段になるよな

- コメント表示したい
- マウスジェスチャ 軌跡の表示
自作ものはジェスチャとコマンドが画像中心に表示される仕様だった
ウインドウを出してたんだな
別に無くても良いんだけど・・・・

- zip内の画像を順に表示できるようにする
一覧、スプレッドシートも必要
リストビューに画像表示させれば良いのかな
自作もののソースを見るか?
- 編集機能はどうしよう
回転は欲しいような気もするが
色調補正は別ソフトじゃ無きゃだめなような・・・
8bfをpythonから使えないかな???

# pillowについて調べた

- 公式
https://pillow.readthedocs.io/en/5.2.x/index.html

- エフェクトはここがわかりやすいね
Qtへの変換も
https://qiita.com/pashango2/items/145d858eff3c505c100a

- タグ取得はここ
https://qiita.com/Gen6/items/88c69ab3a0666895e7a8

- pil はQt変換を標準でサポートしてるのか??
https://dungeonneko.hatenablog.com/entry/2015/07/19/142034
Qpixmapに直接読み込むのとどっちが速いか試してみよう

# pillowを使ってみる

枠はdesignerで作ること
右側にスライダーを縦にいくつか配置しておこう


# 基本

from PIL import Image, ImageQt

img = Image.open('temp.png')

pm = QPixmap.fromImage(ImageQt.ImageQt(img))
lbl = QLabel()
lbl.setPixmap(pm)
lbl.show()

# 明るさ

img.point(lambda x: x * 1.5)    # 1.5倍明るくする
img.point(lambda x: x * 0.5)    # 1 / 2に暗くする
スライダーで値を送るか

# 線画

gray = img.convert("L")
gray2 = gray.filter(ImageFilter.MaxFilter(5))
senga_inv = ImageChops.difference(gray, gray2)
senga = ImageOps.invert(senga_inv)

# 回転

img.rotate(90, expand=True)
im_rotate = im.rotate(45, expand=True, resample=Image.BICUBIC)
 Image.NEAREST: ニアレストネイバー (デフォルト)
 Image.BILINEAR: バイリニア
 Image.BICUBIC: バイキュービック(最高)


# アルファブレンド

Image.blend(img,effect_img, 0.5)

# コントラスト調整

enhancer = ImageEnhance.Contrast(img)
enhancer.enhance(0.0)    # 灰色画像
enhancer.enhance(0.5)    #  ↕

# シャープネス調整

enhancer = ImageEnhance.Sharpness(img)
enhancer.enhance(0.0)    # ボケ画像
enhancer.enhance(0.5)    #  ↕
enhancer.enhance(1.0)    # 元画像
enhancer.enhance(1.5)    #  ↕

-------------------------------------------------------------
# 画像貼り付け

Python, Pillowで画像に別の画像を貼り付けるpaste
https://note.nkmk.me/python-pillow-paste/
位置指定して小さい画像を貼り付けできる

--------------------------------------
# 画像への文字や矩形表示について調べた

- HTMLとしてラベルに表示するやり方があるようだ
http://blog.shibu.jp/article/60706676.html

----
# コンテキストメニュー
考えたら右クリックにはジェスチャを設定していたから普通にコンテキストメニューを使うと反応してしまう

```
def mouseReleaseEvent(self,e)
 if self.ges['cmd'] == '' : # ジェスチャが無い場合はコンテキストメニューを出す
   c_menu.cmenu(e)
 else :
   元のコード
========================================
<< 本体ファイル >>

from PyQt5.QtCore import  Qt 
from custommenu.py import c_menu

__init__
 c_menu(self)
 self.label.setContextMenuPolicy(Qt.CustomContextMenu)
 self.label.customContextMenuRequested.connect(c_menu.cmenu)

label か mainwindow か???

<< 別ファイルで  custommenu.py >>

from PyQt5.QtWidgets import  QAction ,QMenu 


class c_menu():

 def __init__(self,p) :
  self.parent = p

 def c_menu(self,e): # e が来るのかな??
  menu=QMenu(self.parent)

  action = QAction('Open Folder', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)

  action = QAction('AddToList', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)

  # menu.exec_(QCursor.pos ())   
  menu.exec_( e )   
```
# EXIF 表示

https://qiita.com/Gen6/items/88c69ab3a0666895e7a8

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_exif(file,field):

    img = Image.open(file)
    exif = img._getexif()

    exif_data = []
    for id, value in exif.items():
        if TAGS.get(id) == field:
            tag = TAGS.get(id, id),value
            exif_data.extend(tag)

    return exif_data

my_img = "sample.jpg"
print get_exif(my_img,"DateTimeOriginal")
===============わからん==========

```
# まずこれで実験してみよう

from PIL import Image
fname=r''
img = Image.open(file)
exif = img._getexif()

print('exif : ' , exif)
print('items : ' , exif.items() )
```

----
# zip内の画像を順に表示できるようにする

- 結構面倒だよ

とりあえずキーイベントで動作させよう

```
# self.pics=[]  これやめよう

def __init__
 self.current={'pics':[] , 'index':0, 'picslen':0 ,'zipflag':0 }
 self.zip={ 'pics':[] , 'index':0, 'picslen':0}
※このあとで self.pics は全て書き換えること(ここを含めて全8箇所)


def wheel の最後で
 showzip(1) # zip 初期化
 self.current['zipflag'] = 0  or 1

def keyPressEvent (self, e):
 if self.current['zipflag'] :
  if e.key()==Qt.Key_Down :
   self.calcnext( 'inc' )
  if e.key()==Qt.Key_Up :
   self.calcnext( 'dec' )
  showzip(0) # 既存    
  # zipでなければ無視



def showzip( self ,flag ):  # ここは書き換え
        zi = ZipFile( self.current['pics'][self.current['index'] ] , 'r' )
        if flag :
            self.zip['pics'].clear()
            self.zip['pics'] = zi.namelist()
            self.zip['picslen'] = len( self.zip['pics'] )
            self.zip['index'] = 0
        with zi.open( self.zip['pics'][ self.zip['index'] ] ) as z_image :
            pix = QPixmap()    # ここスワップした方が良いのかな
            pix.loadFromData(z_image.read())
            self.label.setPixmap(pix)
            self.resize(pix.width(),pix.height())
            self.show()
        zi.close()


<< サイクル計算するルーチン >>

def calcnext( sign ) :# 増か減か
 if self.current['zipflag'}:
  index = self.zip['index']
  len = self.zip['picslen']
 else:
  index = self.current['index']
  len = self.current['picslen']

 if sign == 'inc':
  index += 1
  if index > (len-1) :
   index=0
 elif sign == 'dec' :
  index -= 1
  if index < 0:
   index = len-1

 if self.current['zipflag'}:
  self.zip['index'] = index
 else:
  self.current['index'] = index
```
- 三項演算子
x = "OK" if n == 10 else "NG"

こうやって書けるのかな?

 if sign == 'inc':
  index = index+1  if index < len-1  else  0
 elif sign == 'dec' :
  index = index-1  if index => 0  else  len-1

# UIの検討

①pngでアルファを持ったグラデ画像を作る
②二画面表示にして左がオリジナル、右が変換後
③左をマスクと切り替えできるようにラジオをつける
④右は常に原画にかぶせるが、ラジオでマスクの適用を切り替える


----

[目次に戻る](https://mimemo.io/m/QORbW4qkvOoda0N)
      

項目画像変換 まず実験こんな感じでどうでしょうExif関係ペンの色を指定pillowについて調べたpillowを使ってみる基本明るさ線画回転アルファブレンドコントラスト調整シャープネス調整画像貼り付け画像への文字や矩形表示について調べたコンテキストメニューEXIF 表示zip内の画像を順に表示できるようにするUIの検討


画像変換 まず実験

マスク画像を重ねる
https://note.nkmk.me/python-pillow-paste/

①デザイナでテスト用のボタン作っておこう
②同じサイズ、8bitグレイスケールのグラデ画像を作っておく

orig=Image.open(< pass >)
grad=Image.open(< pass >)

orig_back=orig.copy()
orig_conv=origk.********

orig_conv_masked = orig_back.paste(orig_conv, (0,0), grad )

 orig_conv_masked   を表示してみる

こんな感じでどうでしょう

fname=r''

with open( fname , 'rb' ) as f :
 data=f.read( 20 )

key=b'\ff\fe'
offset=0
for i in range(len( data )-5):
 if data[i:i+2] == key :
  offset=i
  break

if not offset :
 print('can't find')
 quit()

length = data[offset+3]*256 + data[offset+4]  # ここ逆かも

with open( fname , 'rb' ) as f :
 f.seek(offset+4)
 data=f.read( length )

data.append( b'\00' )

print( data.encode() )

Exif関係

  • ファイル~読み取ったバイナリをbiとして、biはリストなはずだからこんなことで
bi = b'\x00\x01\x02\xff\xfe\x05\x06\x07' 
key = b'\xff\xfe'

for i in range(len(bi)-1):
 if bi[i:i+2] == key :
  print('hit' , i , bi[i+2:i+4])
  break
  • key のバイナリを検索してヒットしたら次のニバイトを取り出す
    これがサイズでそのに文字列がサイズ分入ってる
    pythonのスライスはいいわ!!

  • サイズが10として、① 0a 00 ② 00 0a どっちで書かれてるか?
    いずれにしてもそれぞれを数値に戻してから、どっちかに256を掛けて足せば良い

key1 = b'\x00\x0a'
key2 = b'\x0a\x00'

print( int.from_bytes(key1, 'big') )    ---> 10
print( int.from_bytes(key1, 'little') ) ---> 2560
print( int.from_bytes(key2, 'big') )---> 2560
print( int.from_bytes(key2, 'little') ) --->10

# これでいいか?
print( key1[0]*256 + key1[1] )
print( key1[1]*256 + key1[0] )

後は指定位置から指定バイトを読むだけだ~(^_^)

ペンの色を指定

23.    painter.setPen(Qt.red)
24.    #painter.setPen(QColor(255, 0, 0))
26.    # 使用するフォントを指定
27.    painter.setFont(QFont('Times', 30))
28.    # テキスト描画
29.    painter.drawText(image.rect(), Qt.AlignCenter, 'Symfoware')
30.    # 画像の編集終了
31.    painter.end()

  • コンテキストメニューを作るか
    結構長くなるから別ファイルにしておくか??
    このソフトの機能を呼び出すときの主要な手段になるよな

  • コメント表示したい

  • マウスジェスチャ 軌跡の表示
    自作ものはジェスチャとコマンドが画像中心に表示される仕様だった
    ウインドウを出してたんだな
    別に無くても良いんだけど・・・・

  • zip内の画像を順に表示できるようにする
    一覧、スプレッドシートも必要
    リストビューに画像表示させれば良いのかな
    自作もののソースを見るか?

  • 編集機能はどうしよう
    回転は欲しいような気もするが
    色調補正は別ソフトじゃ無きゃだめなような・・・
    8bfをpythonから使えないかな???

pillowについて調べた

pillowを使ってみる

枠はdesignerで作ること
右側にスライダーを縦にいくつか配置しておこう

基本

from PIL import Image, ImageQt

img = Image.open('temp.png')

pm = QPixmap.fromImage(ImageQt.ImageQt(img))
lbl = QLabel()
lbl.setPixmap(pm)
lbl.show()

明るさ

img.point(lambda x: x * 1.5) # 1.5倍明るくする
img.point(lambda x: x * 0.5) # 1 / 2に暗くする
スライダーで値を送るか

線画

gray = img.convert("L")
gray2 = gray.filter(ImageFilter.MaxFilter(5))
senga_inv = ImageChops.difference(gray, gray2)
senga = ImageOps.invert(senga_inv)

回転

img.rotate(90, expand=True)
im_rotate = im.rotate(45, expand=True, resample=Image.BICUBIC)
Image.NEAREST: ニアレストネイバー (デフォルト)
Image.BILINEAR: バイリニア
Image.BICUBIC: バイキュービック(最高)

アルファブレンド

Image.blend(img,effect_img, 0.5)

コントラスト調整

enhancer = ImageEnhance.Contrast(img)
enhancer.enhance(0.0) # 灰色画像
enhancer.enhance(0.5) # ↕

シャープネス調整

enhancer = ImageEnhance.Sharpness(img)
enhancer.enhance(0.0) # ボケ画像
enhancer.enhance(0.5) # ↕
enhancer.enhance(1.0) # 元画像
enhancer.enhance(1.5) # ↕


画像貼り付け

Python, Pillowで画像に別の画像を貼り付けるpaste
https://note.nkmk.me/python-pillow-paste/
位置指定して小さい画像を貼り付けできる


画像への文字や矩形表示について調べた


コンテキストメニュー

考えたら右クリックにはジェスチャを設定していたから普通にコンテキストメニューを使うと反応してしまう

def mouseReleaseEvent(self,e)
 if self.ges['cmd'] == '' : # ジェスチャが無い場合はコンテキストメニューを出す
   c_menu.cmenu(e)
 else :
   元のコード
========================================
<< 本体ファイル >>

from PyQt5.QtCore import  Qt 
from custommenu.py import c_menu

__init__
 c_menu(self)
 self.label.setContextMenuPolicy(Qt.CustomContextMenu)
 self.label.customContextMenuRequested.connect(c_menu.cmenu)

label か mainwindow か???

<< 別ファイルで  custommenu.py >>

from PyQt5.QtWidgets import  QAction ,QMenu 


class c_menu():

 def __init__(self,p) :
  self.parent = p

 def c_menu(self,e): # e が来るのかな??
  menu=QMenu(self.parent)

  action = QAction('Open Folder', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)

  action = QAction('AddToList', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)

  # menu.exec_(QCursor.pos ())   
  menu.exec_( e )   

EXIF 表示

https://qiita.com/Gen6/items/88c69ab3a0666895e7a8

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_exif(file,field):

img = Image.open(file)
exif = img._getexif()

exif_data = []
for id, value in exif.items():
    if TAGS.get(id) == field:
        tag = TAGS.get(id, id),value
        exif_data.extend(tag)

return exif_data

my_img = "sample.jpg"
print get_exif(my_img,"DateTimeOriginal")
===============わからん==========

# まずこれで実験してみよう

from PIL import Image
fname=r''
img = Image.open(file)
exif = img._getexif()

print('exif : ' , exif)
print('items : ' , exif.items() )

zip内の画像を順に表示できるようにする

  • 結構面倒だよ

とりあえずキーイベントで動作させよう

# self.pics=[]  これやめよう

def __init__
 self.current={'pics':[] , 'index':0, 'picslen':0 ,'zipflag':0 }
 self.zip={ 'pics':[] , 'index':0, 'picslen':0}
※このあとで self.pics は全て書き換えること(ここを含めて全8箇所)


def wheel の最後で
 showzip(1) # zip 初期化
 self.current['zipflag'] = 0  or 1

def keyPressEvent (self, e):
 if self.current['zipflag'] :
  if e.key()==Qt.Key_Down :
   self.calcnext( 'inc' )
  if e.key()==Qt.Key_Up :
   self.calcnext( 'dec' )
  showzip(0) # 既存    
  # zipでなければ無視



def showzip( self ,flag ):  # ここは書き換え
        zi = ZipFile( self.current['pics'][self.current['index'] ] , 'r' )
        if flag :
            self.zip['pics'].clear()
            self.zip['pics'] = zi.namelist()
            self.zip['picslen'] = len( self.zip['pics'] )
            self.zip['index'] = 0
        with zi.open( self.zip['pics'][ self.zip['index'] ] ) as z_image :
            pix = QPixmap()    # ここスワップした方が良いのかな
            pix.loadFromData(z_image.read())
            self.label.setPixmap(pix)
            self.resize(pix.width(),pix.height())
            self.show()
        zi.close()


<< サイクル計算するルーチン >>

def calcnext( sign ) :# 増か減か
 if self.current['zipflag'}:
  index = self.zip['index']
  len = self.zip['picslen']
 else:
  index = self.current['index']
  len = self.current['picslen']

 if sign == 'inc':
  index += 1
  if index > (len-1) :
   index=0
 elif sign == 'dec' :
  index -= 1
  if index < 0:
   index = len-1

 if self.current['zipflag'}:
  self.zip['index'] = index
 else:
  self.current['index'] = index
  • 三項演算子
    x = "OK" if n == 10 else "NG"

こうやって書けるのかな?

if sign == 'inc':
index = index+1 if index < len-1 else 0
elif sign == 'dec' :
index = index-1 if index => 0 else len-1

UIの検討

①pngでアルファを持ったグラデ画像を作る
②二画面表示にして左がオリジナル、右が変換後
③左をマスクと切り替えできるようにラジオをつける
④右は常に原画にかぶせるが、ラジオでマスクの適用を切り替える


目次に戻る