【OpenCV-Python】Canny(Canny edge detection)

Canny edge detectionの処理アルゴリズムついてはこちらのページ

Canny edge detectionの処理アルゴリズム

で紹介していますが、Canny edge detectionで画像のエッジ部分を抽出すると、明確なエッジがなくとも、風景画などの、自然な画像においてもエッジ部分を抽出してくれます。

処理アルゴリズムはやや複雑ですが、OpenCVではCanny()関数を使う事で、簡単にできてしまいます。

 

Canny()関数の構文

Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] ) -> edges

引数

image 入力画像(8bitグレースケールのみ)
threshold1 エッジしきい値(小)
threshold2 エッジしきい値(大)
apertureSize Sobelフィルタ処理のカーネルのサイズ(3, 5, 7 のいずれか)
L2gradient X方向とY方向のSobleフィルタから、エッジの大きさを求める方法
Falseのとき:L1ノルム(X方向の絶対値とY方向の絶対値の和)(初期値)
Trueのとき:L2ノルム(X方向の2乗とY方向の2乗の和の平方根)


戻り値

edges Canny edge detectionの処理画像

サンプルプログラム

Canny edge detection処理のサンプルプログラムを示します。

import cv2

# グレースケールで画像を読み込む
src_img = cv2.imread("image.bmp", cv2.IMREAD_GRAYSCALE)
# Canny edge detection
canny_img = cv2.Canny(src_img, 100, 200)

# 入力画像とCanny edge detectionの処理画像の表示
cv2.imshow("Image", src_img)
cv2.imshow("Canny", canny_img)
cv2.waitKey()

処理結果

 

Cannyのしきい値の決め方

Cannyで処理するエッジのしきい値(threshold1, threshold2)はしきい値(小)としきい値(大)説明しましたが、これだけだと少々わかりづらいかと思いますが、このしきい値は、L2gradientの設定を初期状態で行うと、X方向のSobelフィルタとY方向のSobelフィルタ処理の結果をそれぞれの絶対値の和の画像に対して、非極大抑制を行った画像に対するヒステリシスしきい値の小さい方のしきい値と大きい方のしきい値になります。

と、説明すると余計に分からないw

しきい値の意味合い的には

threshold1 エッジの候補としたいエッジ強度のしきい値(エッジが多めに残る)
threshold2 必ずエッジとして残したい部分のエッジ強度のしきい値(エッジが少なめに残る)

Cannyで処理を行った画像は、threshold2で抽出したエッジと、threshold2のエッジとつながっているthreshold1のエッジを残すようになります。

threshold1、threshold2の値は255を超えた値も有効である事に注意してください。

 

現実的には、どの程度のしきい値が最適なのか?わかりづらいので、threshold1とthreshold2の値を同じ値で、しきい値(小)の値と、しきい値(大)の値のそれぞれのCanny処理後の画像を確認し、最適な値を見つけると良いかと思います。

 

処理例のプログラム

/import cv2

# グレースケールで画像を読み込む
src_img = cv2.imread("image.bmp", cv2.IMREAD_GRAYSCALE)

# しきい値(小)の画像
threshold1 = 100
canny_thre1 = cv2.Canny(src_img, threshold1, threshold1)
# しきい値(大)の画像
threshold2 = 500
canny_thre2 = cv2.Canny(src_img, threshold2, threshold2)

# Cannyフィルタの画像
canny_img = cv2.Canny(src_img, threshold1, threshold2)

# 入力画像とCanny edge detectionの処理画像の表示
cv2.imshow("Image", src_img)
cv2.imshow("threshold1", canny_thre1)
cv2.imshow("threshold2", canny_thre2)
cv2.imshow("Canny", canny_img)

cv2.waitKey()

処理結果

thireshold1(しきい値小)のエッジの中から、thireshold2(しきい値大)のエッジに繋がっている部分を残した画像がCanny処理後の画像になります。

 

参考ページ

Canny edge detectionの処理アルゴリズム

【OpenCV-Python】Sobel(エッジ検出)

【OpenCV-Python】Webカメラから画像をキャプチャして保存する

OpenCVでWebカメラ(USBカメラ)から画像をキャプチャして保存する方法を紹介します。

必要なもの

●Python

●OpenCV(pip install opencv-pythonでOpenCVをインストールします)

●Webカメラ(USBカメラ)

 

サンプルプログラム

OpenCVでカメラから画像を取得し、画像ファイルに保存するサンプルプログラムを以下に示します。

import cv2

# カメラを開く
cap = cv2.VideoCapture(0)

# 画像をキャプチャする
ret, frame = cap.read()

# 画像を保存する
cv2.imwrite("image.jpg", frame)

# カメラを閉じる
cap.release()

これで、Webカメラから画像を取得し、 image.jpg というファイル名で画像が保存されます。

 

次に各コードの説明をします。

 

VideoCapture()

cap = cv2.VideoCapture(0)

の部分で、カメラを開いています。

関数の引数で渡している  は、最初に見つけたカメラを開く事を意味しています。

ほとんどの場合、0 で大丈夫だと思いますが、例えば、PC内臓のカメラのあるノートPCに、別途、USBカメラを刺して使う場合には、この番号を 1 や 2 に調整してみてください。

 

read()

ret, frame = cap.read()

この部分で、現在、撮影している画像データを取得します。

画像の取得し失敗すると ret は Falseになります。

失敗する原因としては、VideoCaptureの部分で指定する番号を間違えたとか、他のプログラムでカメラを使用していた場合などがあります。

frameが撮影した画像データとなります。

 

その他のサンプルを以下に示します。

 

画像をリアルタイムに表示するサンプル

import cv2

# カメラを開く
cap = cv2.VideoCapture(0)

while True:
    # 画像をキャプチャする
    ret, frame = cap.read()

    # 画像を表示する
    cv2.imshow("Image", frame)

    # `q`キーを押すとループを終了する
    if cv2.waitKey(1) == ord('q'):
        break

# カメラを閉じる
cap.release()
# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

このサンプルで q キーを押すまで画像を取得し、表示します。

 

キーを押すたびに連番でファイルに保存するサンプル

import cv2

# カメラを開く
cap = cv2.VideoCapture(0)

indexNo = 0
while True:
    # 画像をキャプチャする
    ret, frame = cap.read()

    # 画像を表示する
    cv2.imshow("Image", frame)

    # `q`キーを押すとループを終了する
    if cv2.waitKey(1) == ord('q'):
        break
    elif cv2.waitKey(1) == ord('c'):
        cv2.imwrite(f"image{indexNo:05d}.jpg", frame)
        indexNo = indexNo + 1
# カメラを閉じる
cap.release()
# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

このサンプルでは、一つ前のサンプルに加えて、 c  キーを入力するたびに、連番のjpegファイルに画像を保存します。

 

read()での画像の取得タイミングについて

ここからが、個人的に興味のあった部分。

画像を取得する際に、read()関数をwhile文で繰り返し呼んでいますが、カメラのフレームレートよりも速くread()関数が呼ばれている可能性が高いです。

このとき、read()関数は、呼ばれるたびに、即、画像データを取得しているのか?それとも、1フーレムの撮影が終わるのを待ってから、画像を取得しているのか?気になった。。

 

そこで、こんなプログラムを実行してみました。

import cv2
import time

# カメラを開く
cap = cv2.VideoCapture(0)

# 撮影開始時間
start = time.perf_counter()
for i in range(300):
    # 画像をキャプチャする
    ret, frame = cap.read()

# 画像300枚を撮影するのにかかった時間
print(time.perf_counter() - start)
# カメラを閉じる
cap.release()
# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

このサンプルプログラムでは、30fpsのカメラを使って、300枚の画像を撮影しています。

 

実際に、プログラムを実行すると、300枚の画像を撮影するのにかっかった時間は、10.4秒という結果になりました。

30fpsのカメラで300枚撮影しているので、計算上は300枚撮影するのに10秒かかる事になり、ほぼ、理論通りの結果となりました。

このことから、read()関数が呼ばれたら、即、画像データを取得しているのではなく、カメラが1フレーム分、撮影が完了するのを待ってから画像を取得しているものと、推測されます。

少なくとも、read()関数を繰り返し呼んでも、同じ画像を重複して取得する事は無さそうです。

【OpenCV-Python】Tkinter GUI Sample

OpenCVのPython版でもC#のようなウィンドウのGUIプログラムを作りたい!

ということで、GUIにTkinterを使って、簡単なサンプルプログラムを作成しました。

 

ここで公開しているコードは自由に変更して使って頂いてもらって構いません。
どこかで公開する場合は、参照元を書いて頂けると嬉しいです。
エラー処理は甘めなので、自己責任でお願いします。

 

機能的には画像ファイル(日本語ファイルを含む)を開いてtkinterのCanvas上に画像を表示します。

画像は、マウス操作で上下左右の移動と、マウスホイールで拡大縮小が可能になっています。

マウスのダブルクリックで画像全体を表示します。

 

OpenCVの処理そのものは二値化とガウシアンフィルタのみの至ってシンプルなものなので、いろいろと追加してお試しください。

 

ソースコードはこちら↓

 

GitHubにもソースコードは上げておきました。

https://github.com/ImagingSolution/OpenCVTkinterGUISample

 

関連記事

【Python】画像ビューア(ズーム(拡大/縮小)、移動表示)

【Python/tkinter】ウィジェットの配置(pack)

【Python/tkinter】ウィジェットの配置(grid)

【Python/tkinter】Label(ラベル)

【Python/tkinter】Button(ボタン)

【Python/tkinter】Entry(テキストボックス)

【Python/tkinter】Menu(メニュー)

【Python/tkinter】Frame(フレーム)

【Python/tkinter】Canvas(キャンバス)の作成

【OpenCV/Python】日本語の画像ファイル読込・保存

【Python】画像データ(NumPy,Pillow(PIL))の相互変換

【OpenCV-Python】findContoursによる輪郭検出

OpenCV(Python)で二値化された画像中の白の部分の外側の輪郭のデータを取得するにはfindContours()関数を用います。
黒の部分の輪郭は、白の部分の内側の輪郭という認識になります。

findContours()関数で取得できる情報は、輪郭を構成している点の座標群と輪郭の内側、外側の情報となります。

さらに、これらの情報を用いて、輪郭の長さや、輪郭の内側の面積、重心、輪郭部分の矩形領域などを取得できる関数も別途、用意されています。

処理例

(入力画像)

(処理結果)

※結果は画像データとしては得られず、上図の色付きの線で書いた部分の情報を取得します。

 

構文

findContours(image, mode, method[, contours[, hierarchy[, offset]]]) ->contours, hierarchy
image 輪郭抽出する画像データ
mode 輪郭構造の取得方法
method 輪郭座標の取得方法
(戻り値)contours 輪郭座標
(戻り値)hierarchy 輪郭の階層情報

 

image

輪郭抽出する画像データを指定します。

画像は8bitのグレースケールで、基本的に二値化された画像を指定します。

一部、32bit1チャンネルのデータ(ラベリングデータ)も指定可能です。

二値化されていない場合は、輝度値が0で無い部分に関しての輪郭情報を取得します。

mode

輪郭の階層情報の取得方法をRETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE, RETR_FLOODFILLの中から指定します。

最初に見つける輪郭が白の外側の輪郭となります。

そのため、入力画像は黒色背景の画像を指定します。

白色背景の画像を指定した場合、最初の輪郭は画像全体となります。

modeで指定した輪郭情報は戻り値のhierarchyに格納されます。

●RETR_TREE

輪郭の階層情報をツリー形式で取得します。

この輪郭の階層情報をというのは、下図を用いて説明します。

まず、一番外側の輪郭(白の領域の外側の輪郭)にがあります。

の内側の輪郭にはがあり、の内側にはがあります。

さらに、

の内側にはがあり、の内側には

の内側には

の内側には

の輪郭があります。

この構造をツリーで表現すると、このようになります。

modeRETR_TREEを指定するとhierarchyの中にこの階層構造が格納されます。

 

●RETR_CCOMP

白の輪郭(外側の輪郭)と黒の輪郭(内側の輪郭)の情報だけを取得し、白の輪郭のさらに内側の輪郭かどうか?の情報は失われます。

この構造をツリーで表現すると、このようになります。

●RETR_LIST

白(外側)、黒(内側)の区別なく、すべての輪郭を同じ階層として取得します。

この構造をツリーで表現すると、このようになります。

●RETR_EXTERNAL

一番外側の白の輪郭だけを取得します。

この構造をツリーで表現すると、このようになります。

method

輪郭を構成する点の座標の取得方法をCHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE, CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOSの中から指定します。

取得した座標は戻り値のcontoursに格納されます。

 

●CHAIN_APPROX_NONE

輪郭上のすべての座標を取得します。

●CHAIN_APPROX_SIMPLE

縦、横、斜め45°方向に完全に直線の部分の輪郭の点を省略します。

 

●CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS

輪郭の座標を直線で近似できる部分の輪郭の点を省略します。

 

(戻り値)contours

輪郭上の座標を取得します。

実際にどのような座標を取得するかは、methodの設定により異なります。

contoursのデータは以下のような配列となります。

contours[輪郭番号][点の番号][0][X座標, Y座標]

 

(戻り値)hierarchy

輪郭の階層情報を取得します。

取得する構造はmodeの設定により異なります。

contoursのデータは以下のような配列となります。

hierarchy[0][輪郭番号][次の輪郭番号, 前の輪郭番号, 最初子供(内側)の輪郭番号, 親(外側)の輪郭番号]

となります。

下図の例について説明します。

輪郭番号の親はで、最初の子供の番号はとなります。

の次の輪郭番号はで、の前の輪郭番号はとなります。

該当する輪郭番号が無い時は -1 になります。

上図の階層情報の例で言うと、

hierarchy[0][0] は [ 3, -1,  1, -1]
hierarchy[0][1] は [-1, -1,  2,  0]
hierarchy[0][2] は [-1, -1, -1,  1]
hierarchy[0][3] は [-1,  0,  4, -1]
hierarchy[0][4] は [-1, -1,  5,  3]
hierarchy[0][5] は [ 6, -1, -1,  4]
hierarchy[0][6] は [-1,  5,  7,  4]
hierarchy[0][7] は [-1, -1,  8,  6]
hierarchy[0][8] は [ 9, -1, -1,  7]
hierarchy[0][9] は [-1,  8, -1,  7]

となります。

 

輪郭座標(contours)の注意点

contoursで取得できる座標は、白の領域を構成する外側の座標、もしくは内側の座標となります。

例えば、下図のような図形の輪郭座標を取得するとき、

白の輪郭を取得するときは、一番、外側の画素の座標(下図の赤い点)がcontoursに格納されます。

しかし、白の内側の黒の輪郭座標は、黒の画素の座標にはなりません

黒の輪郭座標は、輪郭を構成している黒の画素の4近傍の白の画素の座標となります。
黒の輪郭座標は下図の青い点の座標となります。

輪郭の描画

findContours()関数で取得した輪郭(contours)はdrawContours()関数を用いて描画します。

drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) ->image
image 描画先の画像データ
contours 輪郭座標
contourIdx 描画する輪郭の番号
-1にすると、すべての輪郭を描画
color 描画の色を(b, g, r)のタプルで指定します
thickness 線幅
-1を指定すると塗りつぶしになります。
lineType 線の描画スタイルをFILLED, LINE_4, LINE_8, LINE_AAの中から指定します。
hierarchy 輪郭の階層情報を指定します。
maxLevel 輪郭をどの階層まで表示するかを指定します。
0のとき、最初の輪郭のみ
1以降は数値の階層の輪郭すべてが表示されます。
offset

 

サンプルプログラム

import cv2

# 8ビット1チャンネルのグレースケールとして画像を読み込む
img = cv2.imread("sample.bmp", cv2.IMREAD_GRAYSCALE) 

contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE ) 

# 画像表示用に入力画像をカラーデータに変換する
img_disp = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# 全ての輪郭を描画
cv2.drawContours(img_disp, contours, -1, (0, 0, 255), 2)

# 輪郭の点の描画
for contour in contours:
    for point in contour:
        cv2.circle(img_disp, point[0], 3, (0, 255, 0), -1)

cv2.imshow("Image", img_disp)

# キー入力待ち(ここで画像が表示される)
cv2.waitKey()

(実行結果)

 

関連記事

【OpenCV-Python】輪郭(contour)の面積(contourArea)

【OpenCV-Python】輪郭(contour)の矩形領域の取得

【OpenCV-Python】輪郭の周囲長(arcLength)

【Python/Pillow(PIL)】画像の一部を切り抜く

Pillowで画像の一部を切り抜くには、Imageクラスのcropメソッドを用います。

書式は

Image.crop(box=None)
引数 説明
box 切り抜く領域を(左, 上, 右, 下)の座標のタプルで指定します。

 

(サンプルプログラム)

from PIL import Image

# 画像を開く
img = Image.open("Parrots.bmp")

# 画像を切り抜く
img_roi = img.crop((146, 81, 253, 183)) # (left, upper, right, lower)

# 切り抜いた画像の保存
img_roi.save("Parrots_roi.bmp")

(実行結果)

元画像 切り抜き画像

(補足)指定座標について

画像を切り抜く座標の定義ですが、画像の幅がWidth、画像の高さがHeightとすると、
画像の左上が(0, 0)、画像の右下が(Width-1, Height-1)となります。

実際に切り抜かれる画像の領域は、左上の座標(left, upper) を含み、右下の座標(right, lower) の1画素内側の領域が切り抜かれます。

参考

https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.crop

【Python/tkinter】図形の編集(削除、移動、変形など)

線や円などの図形の描画のページでは、tkinterでCanvas上に図形を描画しましたが、描画後に図形の移動や移動や変形、削除などを行う事ができ、その方法を紹介します。

ちょうどWordやExcelのように図形を選択し、移動や変形、削除、表示する順番の変更(最前面へ移動、最背面へ移動)などを行う操作と似ているので、これをイメージしてください。

実際にtkinterで、どのように図形を編集するのか?を紹介します。

tagとid

図形を編集するために、それぞれの図形を識別する必要があり、識別のためにid もしくは tag を用います。

id は create_line のように create_ から始まるメソッドを実行するたびに、1から始まるシリアル番号が返されます。

tag は図形を識別するために、create_ から始まるメソッドの tag オプションに任意文字列を指定します。
この文字列は重複していてもよく、複数の図形に同じtagの名前を指定すると、WordやExcelでいうところのグループ化のような事ができます。

(サンプル)

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

root.mainloop()

(実行結果)

このプログラムを実行すると、id1=1, id2=2 となります。

 

以降は、このサンプルをベースに説明します。
また、tag もしくは idを tagOrId と表現します。

図形の削除(delete)

図形を削除します。

.delete(tagOrId)

.delete(“all”) とすると、Canvas上のすべての図形を削除します。
.delete(id1, “rect”)のように複数のtagOrIdを指定することもできます。

(例)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

# 線の削除(id指定)
canvas.delete(id1)
# 線の削除(tag指定)
#canvas.delete("line")

 

 

 

 

 

図形の相対移動(move)

現在の位置からのX方向、Y方向の移動量を指定して、図形を移動します。(相対移動)

.move(tagOrId, x, y)
tagOrId 移動する図形のid もしくは tag
x X方向(右方向が正)に移動する量
y Y方向(下方向が正)に移動する量

(例)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

# 矩形の移動(相対座標指定指定)
canvas.move(id2, 50, -30)

 

 

 

 

 

図形の拡大縮小(sacle)

点(xOffset, yOffset)を基点とした拡大縮小

.scale(tagOrId, xOffset, yOffset, xScale, yScale)
tagOrId 拡大縮小する図形のid もしくは tag
xOffset 基点となる点のx座標
yOffset 基点となる点のy座標
xScale
X方向(幅方向)の倍率
yScale Y方向(高さ方向)の倍率

(例1)矩形の左上の座標を基点として拡大縮小

# 矩形の描画
id = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")
canvas.create_rectangle(100,50,200,150) # 移動前の位置

# (xOffset, yOffset)を基点とした拡大縮小
canvas.scale(id, 100, 50, 1.5, 0.5) # 矩形の左上の座標を基点に拡大縮小

 

 

 

 

 

(例2)矩形の中心を基点として拡大縮小

# 矩形の描画
id = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")
canvas.create_rectangle(100,50,200,150) # 移動前の位置

# (xOffset, yOffset)を基点とした拡大縮小
canvas.scale(id, 150, 100, 1.5, 0.5) # 矩形の中心を基点に拡大縮小

 

 

 

 

 

図形を構成している座標を指定して変形(coords)

図形を作成した時の座標を書き換えます。

引数にtagOrIdのみを指定すると、図形を構成している座標を[x0, y0, x1, y1, …, xn, yn]のリストで取得します。

.coords(tagOrId, x0, y0, x1, y1, ..., xn, yn)

(例1)図形を構成している座標を指定して変形

# 線の描画
id = canvas.create_line(20, 10, 150, 190, 280, 50, fill = "Red", width = 5, tag="line")
canvas.create_line(20, 10, 150, 190, 280, 50) # 移動前の位置
# 図形を構成している座標を指定して変形
canvas.coords(id, 20, 50, 150, 120, 280, 100)

 

 

 

 

 

(例2)図形を構成している座標を取得し、部分的に座標を変更する

# 線の描画
id = canvas.create_line(20, 10, 150, 190, 280, 50, fill = "Red", width = 5, tag="line")
canvas.create_line(20, 10, 150, 190, 280, 50) # 移動前の位置
# 図形を構成している座標の取得
points = canvas.coords(id)
print(points) # [20.0, 10.0, 150.0, 190.0, 280.0, 50.0]
# 部分的に座標を修正
points[2:4]=[200, 80]
# 図形の変形
points = canvas.coords(id, points)

 

 

 

 

 

前面へ移動(lift)

図形の重なり具合を調整します。

tagOrIdで指定した図形をaboveThisの上へ移動します。

.lift(tagOrId, aboveThis)
tagOrId 重なりを調整する図形のid もしくは tag
aboveThis 移動先の図形のid もしくは tag
指定しない場合、最前面へ移動します。

(例)

# 矩形の描画
id1 = canvas.create_rectangle(20,20,120,120, fill="Red",width = 3)
# 線の描画
id2 = canvas.create_line(5,95,220,95, fill="Green",width = 10)
# 矩形の描画
id3 = canvas.create_rectangle(70,70,170,170, fill="Blue",width = 3)

# 矩形(id3)を矩形(id1)の上へ移動
canvas.lift(id3, id1)

 

 

 

 

 

背面へ移動(lower)

図形の重なり具合を調整します。

tagOrIdで指定した図形をbelowThisの下へ移動します。

.lower(tagOrId, belowThis)
tagOrId 重なりを調整する図形のid もしくは tag
belowThis 移動先の図形のid もしくは tag
指定しない場合、最背面へ移動します。

(例)

# 矩形の描画
id1 = canvas.create_rectangle(20,20,120,120, fill="Red",width = 3)
# 線の描画
id2 = canvas.create_line(5,95,220,95, fill="Green",width = 10)
# 矩形の描画
id3 = canvas.create_rectangle(70,70,170,170, fill="Blue",width = 3)

# 矩形(id3)を最背面移動
canvas.lower(id3)

 

 

 

 

 

参考

https://tkdocs.com/shipman/canvas-methods.html

【Python/tkinter】Canvas(キャンバス)の作成

【Python/tkinter】線や円などの図形の描画

【Python/tkinter】線や円などの図形の描画

前回は、Pillowで線や円などの図形の描画について説明しましたが、今回はtkinterでCanvasウィジェットの上に図形を描画する方法についてです。

前半では、線や矩形、楕円などのメソッドについて説明し、後半にこれらメソッドを用いて下図のような図形を描画するサンプルを示しています。

Pillowとtkinterで大きく異なるのは、Pillowでは画像の上に線などの図形を描画すると、図形データが画像データに反映されましたが、tkinterではCanvasウィジェットの上に図形を配置するイメージとなります。

ちょうどWordやExcelで図形を描画する事に似ています。

Wordの画面

 

Word/Excelでは図形の編集で、図形の移動や選択、削除、配置の順番の最前面へ移動/最背面へ移動などができますが、tkinterでも同様のことが出来ます。

tkinterでの図形の編集方法については図形の編集で説明しています。

ここでは、図形や画像を動画のように繰り返し描画すると、図形のオブジェクトが増え、描画速度が遅くなるため、図形を削除する必要がある事を覚えておいてください。
図形の削除方法は最後の部分に書きました。

簡単なサンプル

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

# 線の描画
canvas.create_line(20, 10, 280, 190, fill = "Blue", width = 5)

root.mainloop()

図形の種類

図形はCanvasクラスにcreate_で始まる名前のメソッドが用意されています。

メソッド名 図形の種類
create_arc 円弧
create_bitmap ビットマップ
create_image イメージ
create_line 直線、折れ線
create_oval 楕円、円
create_polygon ポリゴン(閉じた多角形)
create_rectangle 矩形
create_text 文字
create_window ウィンドウ(ウィジェットの配置)

● 直線、折れ線

id = Canvas.create_line(x0, y0, x1, y1, ..., xn, yn, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
arrow 線の矢印の設定をします。
arrow=tk.FIRST のとき、始点に矢印を追加
arrow=tk.LAST のとき、終点に矢印を追加
arrow=tk.BOTH のとき、両方に矢印を追加
arrowshape 矢印の形状を(d1, d2, d3)のタプルで指定します。
初期値:arrowshape=(8, 10, 3)
capstyle 線の端の形状を設定します。
初期値:capstyle=tk.BUTT
(参考)https://tkdocs.com/shipman/cap-join-styles.html
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 線色を指定します。
joinstyle 折れ線のつなぎ目のスタイルを設定します。
(参考)https://tkdocs.com/shipman/cap-join-styles.html
offset 線のパターン(stipple)のパターンの開始位置を指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 線の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 線の識別用番号

● 矩形(四角形)

id = Canvas.create_rectangle(x0, y0, x1, y1, option, ...)
x0,y0… 左上の座標(x0, y0)と右下の座標(x1, y1)を指定します。
描画される矩形は、(x0, y0)の座標を含み、(x1, y1)より1画素内側に描画されます。
activedash マウスポインタが図形上にあるときの輪郭線の破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが図形上にあるときの塗りつぶしの色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが図形上にあるときの輪郭線の色を設定します。
activeoutlinestipple マウスポインタが図形上にあるときの輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
activewidth マウスポインタが図形上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledoutline
線が無効状態(state=tk.DISABLED)のときの輪郭線の色を設定します。
disabledoutlinestipple 線が無効状態(state=tk.DISABLED)のときの 輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledstipple 線が無効状態(state=tk.DISABLED)のときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 塗りつぶしの色を指定します。
offset 塗りつぶしのパターン(stipple)のパターンの開始位置を指定します。
outline
輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 矩形の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 矩形の識別用番号

● 文字

id = Canvas.create_text(x, y, option, ...)
x, y 文字を表示する位置の座標(x, y)を指定します。
座標の位置(文字の左上や中央など)はanchorオプションに依存します。
activestipple マウスポインタが文字上にあるときの塗りつぶしのパターンを設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
disabledfill 文字が無効状態(state=tk.DISABLED)のときの文字色を設定します。
disabledstipple 線文字無効状態(state=tk.DISABLED)のときの文字のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
fill 文字色を指定します。
font 文字のフォントを指定します。
justify
文字列を複数行のまたぐときの、左寄せ(tk.LEFT)、中央寄せ(tk.CENTER)、右寄せ(tk.RIGHT)を設定します。
offset 線のパターン(stipple)のパターンの開始位置を指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 文字の識別用任意文字列もしくは、文字列のタプルを指定します。
text 描画する文字列を指定します。(日本語可)
width 文字列を描画する領域の幅を指定します。
描画する文字(text)が幅(width)より大きい場合、文字列は押し返し表示されます。
戻り値 id, 線の識別用番号

●楕円、円

id = C.create_oval(x0, y0, x1, y1, option, ...)
x0,y0,x1,y1 左上の座標(x0, y0)と右下の座標(x1, y1)を指定します。
描画される矩形は、(x0, y0)の座標を含み、(x1, y1)より1画素内側に描画されます。
activedash マウスポインタが図形上にあるときの輪郭線の破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが図形上にあるときの塗りつぶしの色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが図形上にあるときの輪郭線の色を設定します。
activeoutlinestipple マウスポインタが図形上にあるときの輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
activewidth マウスポインタが図形上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledoutline
線が無効状態(state=tk.DISABLED)のときの輪郭線の色を設定します。
disabledoutlinestipple 線が無効状態(state=tk.DISABLED)のときの 輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledstipple 線が無効状態(state=tk.DISABLED)のときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 領域を塗りつぶす色を指定します。
offset 塗りつぶしのパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
outlinestipple 輪郭線のパターンを指定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags 楕円の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 楕円の識別用番号

●ビットマップ

ビットマップの描画を行います。
ここでいうビットマップは二値化された画像で、一般的な画像の描画はcreate_imageを用います。
(参考)https://tkdocs.com/shipman/bitmaps.html

id = C.create_bitmap(x, y, *options ...)
x, y ビットマップを表示する位置の座標(x, y)を指定します。
座標の位置(ビットマップの左上や中央など)はanchorオプションに依存します。。
activebackground マウスポインタがビットマップ上にあるときの背景色を設定します。
activebitmap マウスポインタがビットマップ上にあるときのビットマップを設定します。
activeforeground マウスポインタがビットマップ上にあるときのビットマップの色を設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER 
background ビットマップの背景色を指定します。
bitmap 表示するビットマップを指定します。
disabledbackground 無効状態(state=tk.DISABLED)のときの背景色を設定します。
disabledbitmap 無効状態(state=tk.DISABLED)のときのビットマップを設定します。
disabledforeground 線が無効状態(state=tk.DISABLED)のときのビットマップの色を設定します。
foreground ビットマップの色を指定します。
state ビットマップの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags ビットマップの識別用任意文字列もしくは、文字列のタプルを指定します。
戻り値 id, ビットマップの識別用番号

●イメージ

イメージ(Pillow(PIL)のPhotoImage もしくは tkinterのBitmapImage,PhotoImage)の描画を行います。

id = C.create_image(x, y, *options ...)
x, y ビットマップを表示する位置の座標(x, y)を指定します。
座標の位置(ビットマップの左上や中央など)はanchorオプションに依存します。
activeimage マウスポインタが画像上にあるときのイメージを設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
disabledimage 無効状態(state=tk.DISABLED)のときのイメージを設定します。
image イメージを指定します。
通常はPillow(PIL)のPhotoImageを指定します。
state ビットマップの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags イメージの識別用任意文字列もしくは、文字列のタプルを指定します。
戻り値 id, イメージの識別用番号

● ポリゴン

id = Canvas.create_polygon(x0, y0, x1, y1, ..., xn, yn, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが線上にあるときの輪郭線の色を設定します。
activelinestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 塗りつぶす色を指定します。
joinstyle 折れ線のつなぎ目のスタイルを設定します。
tk.ROUND, tk.BEVEL, tk.MITER
(参考)https://tkdocs.com/shipman/cap-join-styles.html
offset 線のパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags ポリゴンの識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, ポリゴンの識別用番号

● 円弧

id = Canvas.create_arc(x0, y0, x1, y1, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが線上にあるときの輪郭線の色を設定します。
activelinestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
extent 開始角度(start)から終了位置までの角度(反時計周りが正)
fill 塗りつぶす色を指定します。
offset 線のパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
start
円弧の開始位置の角度(度)を指定します。3時方向が0度
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
style
円弧のスタイルを指定します。
tk.PIESLICE (初期値) tk.CHORD tk.ARC
tags 円弧の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 円弧の識別用番号

● ウィンドウ

Canvas上にウィジェットを配置します。

id = Canvas.create_window(x, y, option, ...)
x, y 文字を表示する位置の座標(x, y)を指定します。
座標の位置(文字の左上や中央など)はanchorオプションに依存します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
height ウィジェットを配置する幅を設定します。
state ウィンドウの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags ウィンドウの識別用任意文字列もしくは、文字列のタプルを指定します。
width
ウィジェットを配置する高さを設定します。
window 配置するウィジェットオブジェクトを設定します。
戻り値 id, ウィンドウの識別用番号

備考

色の指定は”Red”, ”Green”などの色の名前の文字列を使うか、R,G,Bの順で16進数で指定(#FF0000だと赤)するか、(R,G,B)のタプルで指定します。

(参考)

HTML Color Names
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Py…

楕円や円弧の座標指定位置は、下図のようになります。

サンプル

各種図形のオプション設定を行ったサンプルです。

import tkinter as tk
import os
from PIL import ImageTk

root = tk.Tk()
root.geometry("600x750")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

#######################################
# 線
canvas.create_line(10,   20, 290,  20)                  # オプションなし
canvas.create_line(310,  20, 590,  20, width = 5)       # 線幅5

canvas.create_line(10,   40, 290,  40, arrow=tk.FIRST)  # 始点の矢印
canvas.create_line(310,  40, 590,  40, arrow=tk.LAST)   # 終点の矢印
canvas.create_line(10,   60, 290,  60, arrow=tk.BOTH)   # 両方の矢印
canvas.create_line(310,  60, 590,  60, arrow=tk.BOTH, arrowshape=(24, 25, 8))   # 矢印のサイズ指定

canvas.create_line(10,   80, 290,  80, dash=(5, 3))         # 破線
canvas.create_line(310,  80, 590,  80, dash=(20, 3, 5, 3))  # 破線(1点鎖線)

canvas.create_line(10,  100, 290, 100, width = 15, capstyle=tk.BUTT)        # 終端形状
canvas.create_line(310, 100, 590, 100, width = 15, capstyle=tk.PROJECTING)  
canvas.create_line(10,  120, 290, 120, width = 15, capstyle=tk.ROUND)

canvas.create_line(10,  140, 290, 140, width = 15, stipple='gray12') # 線のパターン
canvas.create_line(310, 140, 590, 140, width = 15, stipple='gray50')

canvas.create_line(10, 160, 150, 180, 300, 160, 450, 180, 590, 160 ) # 折れ線


#######################################
# 矩形
canvas.create_rectangle(10, 200, 290, 220)              # オプションなし
canvas.create_rectangle(310,200, 590, 220, width = 5)   # 線幅5
canvas.create_rectangle(10, 240, 290, 260, fill="Blue") # 塗りつぶしの色指定
canvas.create_rectangle(310,240, 590, 260, fill="Green", outline="Red",width = 2) # 塗りつぶし、輪郭線の色指定

#######################################
# 文字
canvas.create_text(10, 300, text="あいうえお", anchor=tk.NW, font=("",20))   # 基準位置左上
canvas.create_oval(5, 295, 15, 305, fill="Red")

canvas.create_text(300, 300, text="あいうえお", font=("",20))                # 基準位置指定なし(CENTER)
canvas.create_oval(295, 295, 305, 305, fill="Red")

canvas.create_text(590, 300, text="あいうえお", anchor=tk.SE, font=("",20))  # 基準位置右下
canvas.create_oval(585, 295, 595, 305, fill="Red")

canvas.create_text(10, 340, text="あいうえお\nかきくけこ\nさしすせそ", anchor=tk.NW,font=("",20))          # 改行文字
canvas.create_text(310, 340, text="あいうえおかきくけこさしすせそ", anchor=tk.NW, width=120, font=("",20)) # 折り返し幅指定

#######################################
# 楕円
canvas.create_oval(10,450,290, 500)

#######################################
# ビットマップ
canvas.create_bitmap(310,450,bitmap='hourglass')

#######################################
# イメージ
if os.path.exists("Mandrill.png"):
    image = ImageTk.PhotoImage(file = "Mandrill.png")
    canvas.create_image(10,520,image=image, anchor=tk.NW)

#######################################
# ポリゴン
canvas.create_polygon(10,600,150,650,300,600,450,650,550,650)

#######################################
# 円弧
canvas.create_arc(10,670,60, 720)
canvas.create_arc(80,670,130, 720, extent=120)
canvas.create_arc(150,670,200, 720, extent=120, start=30)
canvas.create_arc(220,670,270, 720, extent=120, style=tk.CHORD)
canvas.create_arc(290,670,320, 720, extent=120, style=tk.ARC)

#######################################
# ウィンドウ(Canvas内にウィジェットの配置)
label = tk.Label(root, text = "ラベル", fg = "Red", font = ("", 14, "bold"))
canvas.create_window(300, 740, window=label, width = 300)

root.mainloop()

実行結果

注意点

tkinterのcreate_で始まるメソッドで線や画像などをCanvas上に描画すると、図形が重なっていて見えていなくても、各図形はオブジェクトとして認識しています。
(関数のスコープが外れても、図形のオブジェクトが自動で解放される事はありません。)

そのため、動画のように図形を何回も描画し続けると、オブジェクトの数(描画した図形の数)に比例して描画速度が低下します。

例えば、以下のようなプログラムを実行してみます。

import tkinter as tk
import time

root = tk.Tk()
root.geometry("500x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

colors = ("Red", "Green", "Blue")

for k in range(100):
    start = time.time()
    for i in range(100):
        canvas.create_line(0, i * 2, 500, i * 2, fill = colors[k%3])
    canvas.update()
    # 線100本分の描画時間    
    print((k+1)*100, time.time() - start)

root.mainloop()

実行結果

処理時間

このようにならないように、どこかのタイミングで描画した図形を削除する必要があるのですが、Canvasクラスにdelete()メソッドがあるので、これを用います。

delete()メソッドは、引き数にcreate_XXXXXメソッドで指定したtagの文字列もしくは戻り値のid番号を指定すると、その図形を削除することができます。

また、delete(“all”)と指定することで、すべての図形を削除することも可能です。

そこで、先ほどのプログラムを少し修正して、

import tkinter as tk
import time

root = tk.Tk()
root.geometry("500x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

colors = ("Red", "Green", "Blue")

for k in range(100):
    start = time.time()

    # 図形の削除
    canvas.delete("lines")
    # canvas.delete("all") # ←今回はこれでも同じ

    for i in range(100):
        canvas.create_line(0, i * 2, 500, i * 2, fill = colors[k%3], tag="lines")
    canvas.update()
    # 線100本分の描画時間  
    print((k+1)*100, time.time() - start)

root.mainloop()

処理時間

参考記事

https://tkdocs.com/shipman/canvas.html

【Python/tkinter】Canvas(キャンバス)の作成

【Python/tkinter】図形の編集(削除、移動、変形など)

【Python/tkinter】Canvasに画像を表示する

【Python/Pillow】線や円などの図形の描画

【Python】ファイル、ディレクトリの存在確認

ファイル、ディレクトリの存在を確認するには、osモジュールの isfile, isdir, existsを用います。

isfile ファイルの存在の確認
isdir ディレクトリの存在の確認
exists ファイル もしくは ディレクトリの存在の確認
(ファイル、ディレクトリの区別なく存在確認します)

 

(サンプル)

カレントディレクトリ直下に \images\Porrots.bmp というファイルがある場合の例です。

import os

# ファイルが存在するか?
exist = os.path.isfile("images/Parrots.bmp")
print("ファイルの存在: ", exist)
exist = os.path.isfile("images")
print("ファイルの存在: ", exist)

# ディレクトリが存在するか?
exist = os.path.isdir("images/Parrots.bmp")
print("ディレクトリの存在: ", exist)
exist = os.path.isdir("images")
print("ディレクトリの存在: ", exist)

# ファイルもしくはディレクトリが存在するか?
exist = os.path.exists("images/Parrots.bmp")
print("ファイルもしくはディレクトリの存在: " , exist)
exist = os.path.exists("images")
print("ファイルもしくはディレクトリの存在: " , exist)

(実行結果)

 

注意点

ファイル名を相対パスで指定した場合、カレントディレクトリが移動しているとファイル存在の結果が意図した結果にならない場合があります。

カレントディレクトリを取得するには、osモジュールのgetcwd()メソッドを用います。

(参考)

【Python/os】カレントディレクトリの取得/設定

【Python】tkinterのGUIにmatplotlibのグラフを表示する

matplotlibを使ってグラフを表示すると、通常は、matplotlib独自のウィンドウで表示されますが、これをtkinterのGUIに組み込んで表示する方法を紹介します。

基本的な処理の流れとしては、matplotlibのFigureクラスでグラフの描画領域を確保し、グラフ描画用の座標軸を作成します。

FigureCanvasTkAggクラスで作成したFigureとFigureの配置先のウィジェットを指定し、matplotlib用のキャンバスを作成します。

グラフを描画する時は、作成した軸に対してグラフを描画し、最後にFigureCanvasTkAggクラスで作成したオブジェクトのdraw()メソッドを呼び出して、グラフを表示します。

 

以下にできるだけシンプルにしたサンプルを示します。

import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title('matplotlib graph')

        #-----------------------------------------------

        # matplotlib配置用フレーム
        frame = tk.Frame(self.master)
        
        # matplotlibの描画領域の作成
        fig = Figure()
        # 座標軸の作成
        self.ax = fig.add_subplot(1, 1, 1)
        # matplotlibの描画領域とウィジェット(Frame)の関連付け
        self.fig_canvas = FigureCanvasTkAgg(fig, frame)
        # matplotlibのツールバーを作成
        self.toolbar = NavigationToolbar2Tk(self.fig_canvas, frame)
        # matplotlibのグラフをフレームに配置
        self.fig_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

        # フレームをウィンドウに配置
        frame.pack()

        # ボタンの作成
        button = tk.Button(self.master, text = "Draw Graph", command = self.button_click)
        # 配置
        button.pack(side = tk.BOTTOM)

        #-----------------------------------------------

    def button_click(self):
        # 表示するデータの作成
        x = np.arange(-np.pi, np.pi, 0.1)
        y = np.sin(x)
        # グラフの描画
        self.ax.plot(x, y)
        # 表示
        self.fig_canvas.draw()

root = tk.Tk()
app = Application(master=root)
app.mainloop()

(実行結果)

 

ポイント

Figureは、今回のやり方とは別に、通常のmatplotlibのウィンドウで表示する場合は、

import matplotlib.pyplot as plt

fig = plt.figure()

のようにする場合もありますが、このようにすると、tkinterで作成したウィンドウの×ボタンでプログラムを終了させても、プロセスが終了しない状態になってしまうので、注意が必要です。

参考

https://matplotlib.org/stable/gallery/user_interfaces/embedding_in_tk_sgskip.html

【Python/tkinter】ツールバーの作成

tkinterにはToolBarのような、ツールバー用のウィジェットは無いのですが、ツールバーをFrameButtonを使って作ります。

フレームにアイコン付きのボタンを左側に配置するだけですが。。

(作成したツールバーのイメージ)

  • ファイルを開く
  • フォルダを開く
  • 保存

の3つのボタンを配置しています。

 

(ソースコード)

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk

class Application(tk.Frame):
    def __init__(self, master = None):
        super().__init__(master)

        self.master.title("ToolBar")    # ウィンドウタイトル
        self.master.geometry("300x200") # ウィンドウサイズ(幅x高さ)

        #---------------------------------------
        #  ツールバー
        #---------------------------------------     
        
        # ツールバー用Frame
        frame_toolbar = tk.Frame(self.master, bg = "gray90")
        
        #-------------------------
        # ボタン
        # ファイルを開く
        self.ico_open_file = ImageTk.PhotoImage(file = "OpenFile_16x.png")
        btn_open_file = tk.Button(frame_toolbar, command = self.open_file_click, image = self.ico_open_file)
        # フォルダを開く
        self.ico_open_folder = ImageTk.PhotoImage(file = "OpenFolder_16x.png")
        btn_open_folder = tk.Button(frame_toolbar, command = self.open_folder_click, image = self.ico_open_folder)
        # 保存
        self.ico_save = ImageTk.PhotoImage(file = "Save_16x.png")
        btn_save = tk.Button(frame_toolbar, command = self.save_click, image = self.ico_save)

        #-------------------------
        # ボタンをフレームに配置
        btn_open_file.pack(side = tk.LEFT, padx = (5, 0)) # 左側だけ隙間を空ける
        btn_open_folder.pack(side = tk.LEFT)
        btn_save.pack(side = tk.LEFT)

        #-------------------------
        # ツールバーをウィンドウに配置
        frame_toolbar.pack(fill=tk.X)
        #---------------------------------------     

    def open_file_click(self):
        '''[ファイルを開く]がクリックされたとき'''
        filename = filedialog.askopenfilename()
        print(filename)

    def open_folder_click(self):
        '''[フォルダを開く]がクリックされたとき'''
        dir_name = filedialog.askdirectory()
        print(dir_name)

    def save_click(self):
        '''[保存]がクリックされたとき'''
        filename = filedialog.asksaveasfilename()
        print(filename)

if __name__ == "__main__":
    root = tk.Tk()
    app = Application(master = root)
    app.mainloop()

アイコンファイルはマイクロソフトのVisual Studio Image Libraryより入手しました。

https://www.microsoft.com/en-us/download/details.aspx?id=35825

【Python/Pillow(PIL)】画像データの新規作成

画像データ(PIL.Image)を画像ファイルなどからではなく、新規に作成するには、Imageモジュールのnew関数を使います。

new関数の書式は以下の通り

PIL.Image.new(mode, size, color=0)
mode 画像のモードを設定します。
主なものとして、
“L”      8bitグレースケール
“RGB”  3x8bit カラー画像
詳細はこちらを参照ください。
size 画像のサイズを(幅, 高さ)のタプルで指定します。
color 画像全体のデータの色の値を指定します。
初期値は黒となります。
カラーの場合は、(R, G, B)のように各チャンネルごとの値のタプルで指定します。

 

グレースケール画像を作成するには、以下のようにします。

from PIL import Image

# グレースケールの画像データを作成
img = Image.new("L", (320, 240))
# 画像の表示
img.show()

(実行結果)

初期値を指定すると

# 輝度値を指定して画像データを作成
img = Image.new("L", (320, 240), 128)
# 画像の表示
img.show()

(実行結果)

カラー画像の場合は以下のようにします。

# カラー画像データを作成
img = Image.new("RGB", (320, 240), (0, 128, 255))
# 画像の表示
img.show()

(実行結果)

【Python/Pillow(PIL)】画像ファイルを開く,保存する

jpegやbmpなどの画像ファイルをPillowで開くには、Imageモジュールのopen関数を使います。

同様に画像をファイルに保存するにはsave関数を用います。

以下に、bmp形式の画像ファイルを開き、画像をカラーからモノクロのグレースケールに変換し、pngファイルに保存する例を示します。

from PIL import Image

# PIL.Imageで画像を開く
img = Image.open("Parrots.bmp")

# OS標準の画像ビューアで表示
img.show()

# グレースケールへ変換
img_gray = img.convert("L")
img_gray.show()

# 画像のファイル保存
img_gray.save("image_gray.png")

(実行結果)

 

ファイル名に日本語も指定できる(OpenCVのimread関数は日本語が使えない)ので、使い勝手がいいと思います。

読込、保存のできる画像ファイルのフォーマット(bmp,jegなど)は別途こちら↓にまとめました。

【Python/Pillow(PIL)】対応画像ファイルフォーマット

 

画像ファイルの保存では、jpegファイルでは品質(quality)など、ファイルフォーマットごとに指定できるオプションがあるので、詳細はこちらのページ↓を参照ください。

【Python/Pillow(PIL)】JPEG画像の品質を指定して保存する

【Python】enumerate()関数で配列の要素とインデックス番号を取得

Pythonで配列の各要素をfor文で取得する場合は、以下のようにします。

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for c in colors:
    print(c)

(実行結果)

ここに、インデックス番号付きで各要素をする場合は

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

i = 0
for c in colors:
    print(i, c)
    i += 1

(実行結果)

とも書けますが、Pythonのenumerate()関数を使うと

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for i, c in enumerate(colors):
    print(i, c)

(実行結果)

となります。

さらに開始値を0以外にしたい場合は、enumerate()関数の引数に開始値を追加し、

colors = ['black', 'white', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan']

for i, c in enumerate(colors, 11):
    print(i, c)

(実行結果)

とします。

【Python】特殊メソッド

Python以外でクラスを使ったプログラムを作成すると、クラスをインスタンスした時にはコンストラクタが呼ばれ、クラスオブジェクトを解放した時にはデストラクタが呼ばれます。

コンストラクタやデストラクタのように、ある特定の操作をクラスオブジェクトに対して行った時に呼ばれるメソッドをPythonでは特殊メソッド(Special Method)といいます。

Pythonではインスタンスした時や解放した時以外にも様々な特殊メソッドがあります。

(参考)

https://docs.python.org/ja/3/reference/datamodel.html?highlight=__init__#special-method-names

特殊メソッドはアンダーバー2つ(__)で前後が挟まれたメソッド名となります。

 

Deep Learningのプログラムでは比較的この特殊メソッドが使われるので、実際に使った事のある特殊メソッドを紹介します。

__init__(self [, …])

コンストラクタ

クラスがインスタンスされた時に呼ばれます。

__del__(self)

デストラクタ

del object のように、クラスが解放される時に呼ばれます。

ただし、呼ばれない場合もあります。

どちらかというと、挙動はファイナライザに近いです。

__call__(self [, …])

object(a, b, c)のように、クラスオブジェクトに引き数を追加し、クラスオブジェクトをメソッドのように呼び出します。

__len__(self)

len(object)のようにした時に、要素数(int型)を返します。

何の要素数か?は特に規定はなくユーザー次第となります。

__getitem__(self, key)

object[1]のように、クラスオブジェクトに角カッコ付きで配列のように呼び出した時に要素を返します。

__setitem__(self, key, value)

object[1] = 3のように、クラスオブジェクトに角カッコ付きで配列のように、要素を設定します。

__delitem__(self, key)

del object[key] のようにクラスオブジェクトに角カッコ付きで配列の削除のように呼び出した時に要素を削除します。

サンプル

y = a0 + a1*x + a2*x^2+ a3*x^3 +… となるようなn次関数の係数をコンストラクタで設定し、xの値を__call__メソッドで呼び出し、yの値を取得するサンプルです。

class TestClass:
    '''
    y = a0 + a1*x + a2*x^2+ a3*x^3 +・・・の計算
    '''
    def __init__(self, a):
        ''' コンストラクタ '''
        print("__init__")
        self.coeff = a

    def __del__(self):
        ''' デストラクタ '''
        print("__del__")

    def __call__(self, x):
        ''' 呼び出し可能オブジェクト '''
        print("__call__")

        sum = 0
        for i in range(len(self.coeff)):
            sum += self.coeff[i] * x**i

        return sum

    def __len__(self):
        ''' 要素数 '''
        print("__len__")
        return len(self.coeff)

    def __getitem__(self, index):
        ''' 指定した番号の要素取得 '''
        print("__getitem__")
        return self.coeff[index]

    def __setitem__(self, index, value):
        ''' 指定した番号の要素設定 '''
        print("__setitem__")
        self.coeff[index] = value

    def __delitem__(self, index):
        ''' 指定した番号の要素削除 '''
        print("__delitem__")
        del self.coeff[index]

#------------------------------------------------------

# クラスのインスタンス(__init__メソッドの呼び出し)
object = TestClass([2, 1.5, 3]) # y = 2 + 1.5*x + 3*x**2

# __call__メソッドの呼び出し
print(object(3.5))

# 要素数(__len__メソッドの呼び出し)
print(len(object))

# 要素の取得(__getitem__メソッドの呼び出し)
print(object[1])

# 要素の設定(__setitem__メソッドの呼び出し)
object[1] = 0.5
print(object[1])

# 要素の削除(__delitem__メソッドの呼び出し)
del object[2]
print(len(object))

# クラスの解放
del object

(実行結果)

まとめ

個人的には特殊メソッドはコンストラクタ以外は、あまり使う事はないのですが、例えば画像処理で特殊メソッドを駆使するとすると、ガウシアンフィルタのような畳み込みフィルタでは、コンストラクタでカーネルの係数を設定し、__call__メソッドで画像データを引き数で渡して、フィルタ後の画像データを取得するような使い方ができると思います。

特殊メソッドの呼び出され方は決まっていますが、実際にどのようにつかうか?はユーザー次第なので、うまく使えば、キレイなコードを書く事ができると思います。

【Python】変数がNoneかどうか確認する方法

OpenCVで画像ファイルを開く場合では、ファイルがみつからない、日本語パスのためファイルが読み込めないなどのエラーが起きやすいため、画像の変数がNoneかどうかエラーチェックをしたくなります。

そのため、エラーチェックをしたプログラムを書いてみます。

(ダメな例)

import cv2

# OpenCVで画像ファイルを開く
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED)

if img == None:
    print("Load Error")
else:
    cv2.imshow("Image", img)
    cv2.waitKey(0)

このプログラムは一見良さそうで、実際に img == None のときは、正しく動作します。

しかしながら、 img != None のとき(画像ファイルが正しく読み込めたとき)は以下のような例外が発生します。

The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

例外が発生しないようにするには、 == を使うのではなく、 is を使います。

import cv2

# OpenCVで画像ファイルを開く
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED)

if img is None:
    print("Load Error")
else:
    cv2.imshow("Image", img)
    cv2.waitKey(0)

他にも

if img != None:

としたい場合は

if img is not None:

のように != ではなく、 is not を使います。

【Python/tkinter】LabelFrame(ラベルフレーム、グループボックス)

複数のウィジェットをラベル付きの枠線で囲うウィジェットをLabelFrame(ラベルフレーム)と言います。

tkinter以外ではグループボックスなどと言われます。

このラベルフレームは何かの設定値など、共通の目的を持ったウィジェットを一つにまとめるときに用いられます。

基本的な使い方はFrameに似ていますが、Frameに枠線とラベルが追加されています。

(ラベルフレームの実行例)

(サンプルプログラム)

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master = None):
        super().__init__(master)

        self.master.title("ラベルフレームの作成")     # ウィンドウタイトル
        self.master.geometry("300x200")       # ウィンドウサイズ(幅x高さ)

        #--------------------------------------------------------
        # ラベルフレーム1の作成
        self.labelframe1 = tk.LabelFrame(self.master, text = "フレーム1")
        
        # ラジオボタンに設定する値
        self.radio_value1 = tk.IntVar(value = 0)

        # ラジオボタンの作成
        self.radio1 = tk.Radiobutton(self.labelframe1, text = "項目1", variable = self.radio_value1, value = 0)
        self.radio2 = tk.Radiobutton(self.labelframe1, text = "項目2", variable = self.radio_value1, value = 1)
        self.radio3 = tk.Radiobutton(self.labelframe1, text = "項目3", variable = self.radio_value1, value = 2)
        self.radio1.pack()
        self.radio2.pack()
        self.radio3.pack()

        # ラベルの配置
        self.labelframe1.pack()

        #--------------------------------------------------------
        # ラベルフレーム2の作成
        self.labelframe2 = tk.LabelFrame(self.master, text = "フレーム2", labelanchor = "n", width = 200, height = 100)
        self.labelframe2.propagate(False) # 幅と高さを指定する場合はこの設定が必要

        # ラジオボタンに設定する値
        self.radio_value2 = tk.IntVar(value = 1)

        # ラジオボタンの作成
        self.radio4 = tk.Radiobutton(self.labelframe2, text = "項目1", variable = self.radio_value2, value = 0)
        self.radio5 = tk.Radiobutton(self.labelframe2, text = "項目2", variable = self.radio_value2, value = 1)
        self.radio6 = tk.Radiobutton(self.labelframe2, text = "項目3", variable = self.radio_value2, value = 2)
        self.radio4.pack(anchor = tk.W)
        self.radio5.pack(anchor = tk.W)
        self.radio6.pack(anchor = tk.W)

        # ラベルの配置
        self.labelframe2.pack()
        #--------------------------------------------------------


if __name__ == "__main__":
    root = tk.Tk()
    app = Application(master = root)
    app.mainloop()

構文

オブジェクト = tk.LabelFrame(親ウィジェット, オプション1 = 設定値, オプション2 = 設定値,・・・)

オプション

オプション名 説明
bd 枠線の太さを指定します。(borderwidthと同じ)
borderwidth bdと同じ
bg 背景色を指定します。(backgroundと同じ)
background bgと同じ
cursor ウィジェット上にマウスポインタがある際のカーソルの種類を指定します。
(参考)https://tkdocs.com/shipman/cursors.html
font ラベルのフォントを指定します。
height フレームの高さを画素数で指定します。
highlightbackground
highlightcolor
highlightthickness
labelanchor ラベルの表示位置を指定します。
【設定値】e, en, es, n, ne, nw, s, se, sw, w, wn, ws
labelwidget ラベルの代わりにButtonなどのウィジェットを指定します。
padx フレームの内側に配置するウィジェットまでの横方向の隙間を指定します。
【初期値】0
pady フレームの内側に配置するウィジェットまでの縦方向の隙間を指定します。
【初期値】0
relief フレームのスタイルを指定します。
【設定値】tk.RAISED, tk.GROOVE, tk.SUNKEN, tk.RIDGE, tk.FLAT
takefocus
text ラベルの文字列を指定します。
width フレームの幅を画素数で指定します。

補足説明

ラベルフレームのサイズ(幅と高さ)指定

widthとheightの値を指定しても、デフォルト状態ではLabelFrameのサイズは変わらず、LabelFrameに配置したウィジェットの大きさに合わせて自動調整されます。

この自動調整を無効にするには ラベルフレームオブジェクト.propagate(False) を実行します。

labelanchorについて

labelanchorでラベルの位置を指定します。

実際にラベルが表示される位置は下図を参照してください。

labelwidgetについて

labelwidgetはラベルの代わりにウィジェットを配置することができます。

下図はラベルの代わりにButtonを配置した例になります。

labelwidget = ウィジェットのオブジェクト

のように指定します。