tkinterで画像ビューア(Canvas.create_image周りの補足)


209行目のoffsetや253行目のcreate_image周りを整理する。

・基本

canvas_width = 400
canvas_height = 400
self.canvas = tkinter.Canvas(self.master, bg='red', width=canvas_width, height=canvas_height)
self.canvas.pack()
self.img = Image.open('sora.png')
self.tk_img = ImageTk.PhotoImage(self.img)
self.canvas.create_image(
canvas_width // 2, canvas_height // 2, image=self.tk_img, anchor='c'
)

create_imageは、canvasの(canvas_width//2, canvas_height//2)の位置に画像の中心を持ってくるという命令。anchorの対象が"canvas"ではなく"画像"であることに注意。anchorのデフォルトは"c"。

・アフィン変換

mat = np.eye(3)
mat[0, 2] = float((canvas_width - self.img.width) / 2)
mat[1, 2] = float((canvas_height - self.img.width) / 2)

inv_mat = np.linalg.inv(mat)
pil_transformed_image = self.img.transform(
(canvas_width, canvas_height),
Image.AFFINE,
tuple(inv_mat.flatten()),
Image.NEAREST,
)

self.tk_img = ImageTk.PhotoImage(pil_transformed_image)
self.canvas.create_image(
canvas_width // 2, canvas_height // 2, image=self.tk_img, anchor='c'
)

matは、画像中心をキャンパス中心に持っていく行列。
transformで(canvas_width, canvas_height)の画像を生成。
create_imageは「基本」と同じでOK。上記サイトのように(0, 0, anchor='nw')にする必要はない。なお、逆に「基本」で(0, 0, anchor='nw')を使うと表示がおかしくなるので注意。画像中心をキャンパス中心に持っていった場合のみ使える。


tkinterのpack

〇1要素のみ
・side="left", fill="none", expand=False

 

・side="left", fill="both", expand=False

fillして縦のみ染まるということは、縦のみ元々expandされている(領域としては確保されているが、fillしていない)状態だったということ。

・side="left", fill="none", expand=True

元々縦のみexpandされていたものが、横もexpandされる。
なので、side="left"としても、中央に表示される。

・side="left", fill="both", expand=True

縦横にexpandしてfillするので、全領域がcanvasになる。
TreeViewでも同様の結果になった。

 

〇2要素

root.geometry("1350x900")
canvas = tk.Canvas(root, bg="red", width=900, height=900)
canvas.pack(side='left')
canvas.create_image(450, 450, image=image)
tree = ttk.Treeview(root)

・tree.pack(side='right')

縦のみexpandされているので、縦は中央に配置される。
横は空いてるので、side='right'によって右詰めされる。

・tree.pack(side='right', fill="both")

縦のみexpandされているので、そこがfillされる。

・tree.pack(side='right', expand=True)

横にもexpandされる。fillしてないので、上下左右に隙間ができて中央配置される。

・tree.pack(side='right', expand=True, fill="both")

横にもexpandされ、上下左右にfillされる。

〇3要素
leftで左側を占有(canvas
その後topで、空いている右領域の上側を占有(inspector)
最後にbottomで、右下領域を占有(treeview)

 

Photo2Illust

・彩度を上げる
+20くらいがおすすめされている。+70くらいまではいける。

ciel.s on Twitter: "風景写真からアニメ背景風イラストにする方法の解説です!! https://t.co/CUjrsALPB1" / Twitter

コントラストを上げろって言う人と下げろって言う人がいる。
コントラストを下げるのは編集で飛ばないようにするため。
上げ下げは意図に応じて変える。とにかく彩度が大事。
どうせ彩度を上げるなら、賢くやってくれるHDRトーンが良いかも。

・フィルタ

線分追跡

import numpy as np
import cv2


def track(img, chain_codes, x, y):

prev_x = x
prev_y = y
prev_code_idx = 2

line = []
while True:
code_idx = (prev_code_idx + 6) % 8
find_flag = False
# 90度より大きく曲がる方向は調べない
while code_idx != (prev_code_idx + 3) % 8:
code = chain_codes[code_idx]
x = prev_x + code[0]
y = prev_y + code[1]
if img[y, x] == 255:
find_flag = True
break
code_idx = (code_idx + 1) % 8
if not find_flag:
break
prev_code_idx = code_idx
prev_x = x
prev_y = y
line.append([x, y])

return line


def main():

img = cv2.imread('line2.png', 0)
img = 255 - img

# 最も左上の画素をスタートにする
y = np.argmax(np.max(img, axis=1))
x = np.argmax(img[y])

chain_codes = [
[-1, 1], [0, 1], [1, 1], [1, 0],
[1, -1], [0, -1], [-1, -1], [-1, 0]
]
line1 = track(img, chain_codes, x, y)

rev_chain_codes = [
[1, 0], [1, 1], [0, 1], [-1, 1],
[-1, 0], [-1, -1], [0, -1], [1, -1]
]
line2 = track(img, rev_chain_codes, x, y)

if line1[-1] == line2[-1]:
all_lines = line1
else:
line1.reverse()
all_lines = line1 + line2


if __name__ == '__main__':
main()

BufferedImageからOpenCVのMatへ変換

Java2DFrameUtilsで可能なので、以下の方法は不要
Java2DFrameUtils (JavaCV 1.5.7 API)


ただし、Java2DFrameUtilsに対応するには
javacv-〇.〇.〇.jar
が追加で必要になる。

・BufferedImage -> Mat
val byteArrayOutputStream = ByteArrayOutputStream()
ImageIO.write(bufferedImage, "png", byteArrayOutputStream)
mat = opencv_imgcodecs.imdecode(Mat(*byteArrayOutputStream.toByteArray()), opencv_imgcodecs.IMREAD_UNCHANGED)

 

・Mat -> BufferedImage
val byteArray = ByteArray(mat.arraySize().toInt())
opencv_imgcodecs.imencode(".png", mat, byteArray)
return ImageIO.read(ByteArrayInputStream(byteArray))

java - Converting `BufferedImage` to `Mat` in OpenCV - Stack Overflow