291.ラズパイ無双[24 ARマーカー(おまけ)]
初回:2022/12/21
Raspberry Pi (ラズベリーパイ、通称"ラズパイ")で何か作ってみようという新シリーズです。前回『ARマーカー』のプログラムをご紹介しましたが、今回は『ARマーカー』でちょっと遊んでみたいと思います。
P子「どうせ、大したことは無いんでしょ」※1
まあ、大したことは無いんですけど、先に言われると悲しいです。
何となく、ArUcoマーカーが異世界転生の文字のように見えたので、そこで何か用意しようかと思いました。例えば、1から26番までの数字をアルファベットに置き換えて英語の文章を作ったり、日本語を割り当てたり...
P子「50音って言っても、濁点や半濁点(丸)、促音(そくおん=つまる音[っ])や拗音(ようおん=[ゃ,ゅ,ょ])もあるわよ」
『や、ゆ、よ、わ、を、ん』で、46文字、濁点、丸、文字を小さくする記号で、49文字。カタカナで使われる長音も含めると、50文字で足りそうです。
P子「そんなに使ったら、数字とか表せないわよ」
なら、X-Y でマトリクスを作って変換表に割り当ててもいいです。が、そんなややこしい事をすると面白みがなくなるので、もっと簡単にした方が良いかもしれません。英語なら、ASCIIコードで引き算すれば、0からの数字に変換できます。
P子「それはそれで、単純すぎるわね」
と、いう事で、年末も近いので来年のカレンダーを作成してみたいと思います。
P子「はあ?」
【目次】
1.ソースコード
まずは、ソースコードを先に提示しておきます。
import cv2 from cv2 import aruco # ARマーカー画像作成 import numpy as np import sys import os import calendar # カレンダー情報を作成する WHITE = (255, 255, 255) # 生成するマーカー用のパラメータ size = 76 # マーカーのサイズ top,bottom,left,right = 10,10,10,10 # 余白のピクセル # 白色画像 高(h)+上下ボーダー,幅(w)+左右ボーダー imgZero = np.ones([size+top+bottom,size+left+right],np.uint8)*255 ### --- マーカーを生成 --- ### dict_aruco = aruco.Dictionary_get(aruco.DICT_4X4_50) # 50種類のマーカー def arImage( no ) : if no == 0 : img = imgZero # 0 は空白に変換 else: img = aruco.drawMarker(dict_aruco, no, size) # マーカー作成 # 余白作成 img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=WHITE) return img def makeMonth(Y,M): mList = [0,0,0,M,0,0,0] # カレンダの月のヘッダー情報 tList = [] # タイトル画像のリスト for i in mList : tList.append(arImage(i)) # 個別の画像リストを作成 im_h = cv2.hconcat(tList) # 画像を横向けに連結 vList = [] # 縦に積み上げる画像のリスト vList.append(im_h) # タイトル画像のリスト追加 calList = calendar.monthcalendar(Y, M) # デフォルトは月曜始まり for week in calList : # 月内の週の日付リスト hList = [] # 横に追加する画像リスト(初期化) for day in week: # 週内の日付リスト hList.append(arImage(day)) # 週内の日付の画像 im_h = cv2.hconcat(hList) # 週内の日付画像を横に連結する。 vList.append(im_h) # 週の画像のリスト im_hv = cv2.vconcat(vList) # 週の画像のリストを縦に連結する return im_hv if __name__ == "__main__" : print('python3 calendarTest.py 2023 1') args = sys.argv Y = int(args[1]) # 年 M = int(args[2]) # 月 img = makeMonth(Y,M) cv2.imshow('CALENDAR', img) # 画面表示 k = cv2.waitKey(0) # キーボード入力あるまで待機 path = f'/tmp/{Y}_{M:02}.png' # yyyy_mm 形式 cv2.imwrite(path, img) # 保存 cv2.destroyAllWindows()
2.解説1 カレンダークラス
カレンダーの作成には、Pythonの標準ライブラリである、calendarモジュールを使用します。
≪参考1≫
https://docs.python.org/ja/3/library/calendar.html
calendar --- 一般的なカレンダーに関する関数群
calendar.monthcalendar(year, month) を使用します。
翻訳『月のカレンダーを表すマトリックスを返します。 各行は週を表します。 月以外の日はゼロで表されます。 setfirstweekday() で設定しない限り、毎週月曜日から始まります。』
P子「この関数の説明の所だけ、日本語がないのよね」
つまり、この関数の戻り値は、カレンダーの行列の形の配列で返され、数字の無い箇所は、ゼロ となるという事です。今回、数字のある個所は、そのまま Arucoマーカーに置き換え、ゼロ の箇所は空白にすればよいという事です。
3.解説2 白色画像
ゼロとなる箇所は、空白にしたいので、マーカーと同じ大きさの白色画像を用意します。
size = 76 # マーカーのサイズ top,bottom,left,right = 10,10,10,10 # 余白のピクセル # 白色画像 高(h)+上下ボーダー,幅(w)+左右ボーダー imgZero = np.ones([size+top+bottom,size+left+right],np.uint8)*255
Arucoマーカー は、size で指定した大きさで作成されますが、くっつけると境界線がなくなるため、認識できません。そこで、各マーカーには余白を付ける必要がありますが、その分を考慮した白色画像を作成しておきます。
ここでは、要素が1の配列を生成するnumpy.ones関数を使用しています。
numpy.ones(shape, dtype=None, order ='C')
shapeに、高(h)+上下ボーダー,幅(w)+左右ボーダー を指定しています。最後の *255 で白色画像にしています。
blank = numpy.zeros(shape, np.uint8)
blank += 255
でも、良いでしょう。
4.解説3 余白作成
先ほども少し説明しましたが、Arucoマーカーで作成した画像は、周りが黒枠になっており、その外に白枠が必要です。画像を連結する場合、余白を用意しないと認識できなくなります。余白の作成方法は、色々と考えられますが、ここでは、cv2.copyMakeBorder を使用します。
≪参考2≫
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_core/py_basic_ops/py_basic_ops.html#id6
画像の境界領域を作る(パディング)
WHITE = (255, 255, 255) img = aruco.drawMarker(dict_aruco, no, size) # マーカー作成 # 余白作成 img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=WHITE)
入力画像、各境界の線幅、境界の種類、そして、境界の種類がBORDER_CONSTANTの場合の境界の色を指定します。
マーカーを作成して、それを引数に使う事で、マーカーに余白を追加しています。
5.解説4 画像の連結
カレンダーで、日付単位に画像を作成した場合、まずは横に7個連結します。先に述べたように、ゼロの場合は、空白を追加します。数字をArucoマーカー画像に変換しているのは、makeMonth(Y,M) メソッドです。
この中で、日付から1週間分の画像にするのに、cv2.hconcat を使用して画像を横に連結します。引数には、画像のリストを用意します。
そこで連結できた1週間分の画像を、リストに登録して、今度はcv2.vconcat を使用して縦に連結します。
for week in calList : # 月内の週の日付リスト hList = [] # 横に追加する画像リスト(初期化) for day in week: # 週内の日付リスト hList.append(arImage(day)) # 週内の日付の画像 im_h = cv2.hconcat(hList) # 週内の日付画像を横に連結する。 vList.append(im_h) # 週の画像のリスト im_hv = cv2.vconcat(vList) # 週の画像のリストを縦に連結する
≪参考3≫
https://kangkang1981.hatenablog.com/entry/2020/05/13/161718
Python : 画像を縦、横に連結(vconcat,hconcat)
画像の連結は、例えば、画像処理の前後の画像を連結して表示する場合に見やすくなると思います。
6.まとめ
折角なので、来年の1月のカレンダーを作成してみましょう。
$ python3 calendarTest.py 2023 1
今回は『ARマーカー』で遊んでみましたが、色々な用途に応用できそうです。
P子「これからが楽しみね」
ほな、さいなら
======= <<注釈>>=======
※1 P子「どうせ、大したことは無いんでしょ」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。