#前書き
前回はマインスイーパの作り方を紹介したが、今回は時計を簡単に作れるかを考えてみる。
頑張れば時計の模様(円や数字など)もかけることはできるが、ここでは、画像として導入したケースを紹介する。その理由は、作成者オリジナルの時計模様画像に一般化できるためである。
#環境
MATLABのR2019aバージョン
Windows10
MATLAB Toolbox: Image Processing Toolbox
#全体のフロー
プログラム作成のフロー:
1.オリジナルの時計画像を作成
2.時計の中心や針などを定義
3.時間と共に時計の針の角度計算や位置更新
オリジナルの時計画像を作成
図1のような簡単な画像を作成した。今回紹介する事例では、作成者オリジナルの時計画像に対応するようにしているが、条件として、円形の時計のみが対象となる。
図1:著作者オリジナルの時計画像
時計の中心や針などを定義
まずは、MATLABのimfindcircles関数を利用して上記オリジナル画像よりその中心を求める。
以下コードではMATLABのビルトイン関数IMFINDCIRCLESで画像から中心を求めているが(汎用性の高度化を目的で)、
基本的に、画像ごと、中心の位置をメタデータとして記録しておけば、そのまま取り組んでも大丈夫。
次は、その中心から円周方向に伸びる3本の針(時、分、秒)を定義する。
時と分の針を時計らしく太めにするため、二本の直線で表現する。
これらの二本の直線は円の中心側でお互い隔ており、円周側で一体になっている。
コードは以下になる(コメントもご参照):
% パラメータ
offst = 1;
rH = 60;
rM = 80;
rS = 110;
radrange = [100 180];
% 自作のオリジナル画像を取り組む
I = imread('BaseWatch3.jpg');%図1の画像はこのファイルにある
I = flipud(I);
[c,r] = imfindcircles(I,radrange);%画像中心計算
%画像の取り組み
figure('ToolBar','none','menubar','none')
hI = imshow(I); %画像表示
set(gca,'YDir','normal') %画像表示におけるY軸の方向を通常の直交座標に合わせる
hold on
plot(c(1),c(2),'k.','Markersize',15) %中心に例えば黒い丸を描く
%針の定義・初期化
hlH1= line([c(1) c(1)],[c(2) c(2)], 'Color','Blue', 'Linewidth',2);%時の針⓵
hlH2= line([c(1) c(1)],[c(2) c(2)], 'Color','Blue', 'Linewidth',2);%時の針⓶
hlM1= line([c(1) c(1)],[c(2) c(2)], 'Color','Red', 'Linewidth',1);%分の針⓵
hlM2= line([c(1) c(1)],[c(2) c(2)], 'Color','Red', 'Linewidth',1);%分の針⓶
hlS = line([c(1) c(1)],[c(2) c(2)], 'Color','Black', 'Linewidth',1);%秒の針
時間と共に時計の針の角度計算や位置更新
MATLABで簡単に現在時刻を読み込んだり、その中から、時、分や秒の値を分離することができる。
この値に応じて、それぞれの針の位置を更新すればいい。
それぞれの針は、片方(円中心側)の位置が常に円の中心にあるので、求めるべきことは、それぞれの針の円周側の位置(X,Y座標)がどうなるかとのことである。
そのため下記ワークフローを考える:
(1)時、分や秒について、その現在値に基づいてそれぞれの針の角度を求める。
このため、以下の関数getAngles()をご参照。
(2)求めた角度と針の長さ情報を利用して、円柱座標から直交座標に変換によって、針の円周側の位置を求める(X,Y座標)。
(3)それぞれの針の新規位置に関する表示を更新する
最後に、Whileループの中に上記(1)~(3)を繰り返していけば、時計の出来上がりである。
※ちなみに、今回は40行以下で済んだとのこと。
while isvalid(hI)
%時、分、秒の値を分離
hms = datestr(now,'hh-MM-ss');
hr = str2double(hms(1:2));
if hr > 12
hr = hr - 12;
end
mn = str2double(hms(4:5));
ss = str2double(hms(7:8));
%時間の針の処理
[aH,aM,aS] = getAngles(hr,mn,ss);
[x, y] = pol2cart(aH,rH);
adjustPosition(c,x,y,[hlH1,hlH2],offst+1);
%分の針の処理
[x, y] = pol2cart(aM,rM);
adjustPosition(c,x,y,[hlM1,hlM2],offst);
%秒の針の処理
[x, y] = pol2cart(aS,rS);
adjustPosition(c,x,y,hlS,offst);
end
getAngles()関数
function [aH,aM,aS] = getAngles(hr,mn,ss)
aH = deg2rad(90 - hr*30 - mn*0.5 - ss*(1/120));
aM = deg2rad(90 - mn*6 - ss*(1/10));
aS = deg2rad(90 - ss*6);
end
adjustPosition()関数
function adjustPosition(c,x,y,hndls,offst)
p = [c(1)+x c(2)+y];
if numel(hndls)>1
set(hndls(1),'XData',[c(1)-offst p(1)],'YData',[c(2)-offst p(2)]);
set(hndls(2),'XData',[c(1)+offst p(1)],'YData',[c(2)+offst p(2)]);
else
set(hndls,'XData',[c(1) pS(1)],'YData',[c(2) pS(2)]);
end
drawnow
end