検索:
OpenCVとPythonで硬貨を検出してみた

OpenCVをPythonで走らせてコインの認識を行ってみました。

まずはカメラの映像をライブでウィンドウにキャプチャします。

Python
import cv2

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

while True:

    # 画像をキャプチャする
    ret, frame = cap.read() #カメラ動画
    
    # 画像の表示
    cv2.imshow("Image", frame)
    
    # `q`キーを押すとループを終了する
    if cv2.waitKey(1) == ord('q'):
        break

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

# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

実行結果がこちら↓↓

接続するカメラが違う場合は、4行目の関数の閾値の数字を変えてみてください。これでUSBカメラの映像をライブで取り込めるようになりました。

次に Hough 関数を使って円を検出してみます。

Python
import cv2
import numpy as np

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

#フォントの指定
fontType = cv2.FONT_HERSHEY_DUPLEX

while True:

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

    # グレースケール画像の生成
    image_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

    #==============================================
    # Cannyでエッジ検出処理
    canny_gray = cv2.Canny(image_gray,100,200)
    cimg = canny_gray

    j = 0
    
    # hough関数
    circles = cv2.HoughCircles(cimg, cv2.HOUGH_GRADIENT, 1, 20, param1 = 120, param2 = 15, minRadius = 10,maxRadius = 30)
        # param1 : canny()エッジ検出器に渡される2つの閾値のうち、大きいほうの閾値0
        # param2 : 円の中心を検出する際の投票数の閾値。小さくなるほど、誤検出が起こる可能性がある。
        # minRadius : 検出する円の最小値
        # maxRadius : 検出する円の最大値

    #検出された際に動くようにする。
    if circles is not None and len(circles) > 0:

        #型をfloat32からunit16に変更。
        circles = np.uint16(np.around(circles))
        
        for i in circles[0,:]:
            # 外側の円を描く
            cv2.circle(frame,(i[0], i[1]), i[2], (0, 191, 255), 2)
            # 中心の円を描く
            cv2.circle(frame,(i[0], i[1]), 2, (255, 255, 0), 2)
            # 円の数を数える
            j = j + 1

    #円の合計数を表示
    cv2.putText(frame,'Total :'+str(j), (30,30), fontType, 1, (0, 0, 0), 1, cv2.LINE_AA)

    #==============================================

    # 画像の表示
    cv2.imshow("Image", frame)
 
  # `s`キーを押すと画像を保存する
   if cv2.waitKey(1) == ord('s'):
        #結果の書き込み
        cv2.imwrite('image1.jpg',frame)   
  
    # `q`キーを押すとループを終了する
    if cv2.waitKey(1) == ord('q'):
        break

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

# すべてのウィンドウを閉じる
cv2.destroyAllWindows()

実行結果がこちら↓↓

これで円形状のものを検出し、数をカウントできるようになりました。

慣性モーメントを分かりやすく説明してみた

「慣性モーメント(イナーシャ)」とは

<抽象度★★★★★>

物体の「回りにくさ」「止まりにくさ」を表す値です。


<抽象度★★★★☆>

直動系の超有名な方程式(ニュートンの運動の法則)
$$ F=ma =m \ddot x$$

[N] = [kg] [m/s2]

を回転系に直すと

$$ \tau =Ja= J \ddot \theta $$

[Nm] = [kg・m2] [rad/s2]

となり、ここに出てくる「J」が「慣性モーメント[kg・m2]」です。

すなわち、回転系における「重さ」を示す値と言えます。


<抽象度★★★☆☆>

機械設計において、慣性モーメントはモータの容量を計算する際に必要になります。

台形の速度プロファイルで回転体の位置決めをする場合、「角加速度」に「慣性モーメント」をかけると、モータに必要なトルクが分かります。(摩擦などの負荷トルクは無視しています)

慣性モーメントが大きいと必要なトルクが大きくなり、慣性モーメントが小さいと必要なトルクが小さくなることが分かります。


<抽象度★★☆☆☆>

下図のような質点mの回転を考えます。

この時、中心軸周りの回転の慣性モーメントは、

$$ J = mr^2 $$

で表されます。

ここで重要なのは、回転半径 \( r \) が大きいほど慣性モーメントが \( r^2 \) に比例して大きくなる点です。

つまり、同じ質量の物体でも、回転軸から遠い位置に質量があるほど「回しにくく・止めにくく」なります。

複数の質点がある場合は、それぞれの寄与を足し合わせます。

$$ J = \sum_i m_i r_i^2 $$


【円柱(ソリッドシャフト)の慣性モーメント】

実際の機械部品は質点ではなく体積を持つ物体です。均質な円柱(半径 \( R \)、質量 \( M \))の中心軸周りの慣性モーメントは、上の式を積分することで求められ、

$$ J = \frac{1}{2}MR^2 $$

となります。

たとえば、モータシャフトに取り付けるプーリーやフライホイールを設計する際は、この式を使って慣性モーメントを見積もります。

$$ J = \frac{1}{2}MR^2 = \frac{1}{2} \times \rho \times \pi R^2 L \times R^2 = \frac{\rho \pi L R^4}{2} $$

(\( \rho \):密度、\( L \):長さ)

半径 \( R \) が2倍になると慣性モーメントは 16倍(\( R^4 \) に比例)になるため、外径を大きくする際は注意が必要です。


【中空円筒(パイプ形状)の慣性モーメント】

内径 \( R_1 \)、外径 \( R_2 \) の中空円筒の場合は、

$$ J = \frac{1}{2}M(R_1^2 + R_2^2) $$

となります。

同じ質量でも中空にすることで外径を大きく取れるため、剛性を保ちながら慣性モーメントを効率よく増やしたい(フライホイール)場合や、逆に軽量化しながら慣性を抑えたい(高速回転ローラー)場合に活用されます。

これらの基本形状の慣性モーメントを組み合わせることで、複雑な機械部品の慣性モーメントも計算できます。


<抽象度★☆☆☆☆>

【実際の設計例:モータ選定での慣性モーメント計算】

例として、ステンレス製のローラー(円柱)をサーボモータで回転させる場合を考えます。

  • 材質:ステンレス(密度 \( \rho = 7900 \, \mathrm{kg/m^3} \))
  • 外径:\( \phi 100 \, \mathrm{mm} \)(半径 \( R = 0.05 \, \mathrm{m} \))
  • 長さ:\( L = 200 \, \mathrm{mm} = 0.2 \, \mathrm{m} \)

① ローラーの質量を求める

$$ M = \rho \pi R^2 L = 7900 \times \pi \times 0.05^2 \times 0.2 \approx 12.4 \, \mathrm{kg} $$

② ローラーの慣性モーメントを求める

$$ J = \frac{1}{2}MR^2 = \frac{1}{2} \times 12.4 \times 0.05^2 \approx 1.55 \times 10^{-2} \, \mathrm{kg \cdot m^2} $$

③ 必要トルクを求める

台形の速度プロファイルで、0.1秒で100 rpm まで加速したい場合:

$$ \omega = 100 \, \mathrm{rpm} = \frac{100 \times 2\pi}{60} \approx 10.5 \, \mathrm{rad/s} $$

$$ \dot{\omega} = \frac{10.5}{0.1} = 105 \, \mathrm{rad/s^2} $$

$$ \tau = J \dot{\omega} = 1.55 \times 10^{-2} \times 105 \approx 1.63 \, \mathrm{Nm} $$

モータの定格トルクがこの値を上回るものを選定すればOKです(実際には摩擦トルクや安全率も加味します)。


【設計のポイント:イナーシャ比】

モータ選定では慣性モーメントの絶対値だけでなく、モータ自身の慣性モーメント \( J_M \) に対する負荷側の慣性モーメント \( J_L \) の比(イナーシャ比)も重要です。

$$ \text{イナーシャ比} = \frac{J_L}{J_M} $$

イナーシャ比が大きすぎると、モータが負荷をうまく制御できず発振や整定時間の悪化につながります。一般的なサーボシステムでは、メーカー推奨のイナーシャ比(目安:30倍以下)に収めることが推奨されています。

イナーシャ比が大きくなる場合の対策としては、以下が挙げられます。

  • ローラーの外径を小さくする(\( J \) は \( R^4 \) に比例するため効果大)
  • 中空構造にして質量を減らす
  • 減速機を挟む(減速比 \( n \) の2乗分だけ負荷慣性をモータ側から見て小さくできる)

減速機を挟んだ場合、モータ軸から見た負荷の慣性モーメントは

$$ J_L’ = \frac{J_L}{n^2} $$

となり減速比の2乗に比例するため、イナーシャ比の改善に非常に有効です。