
よく画像処理で OpenCV というのは聞くけれど、何ができるのか?がわからない方も「今から時短入門」!
こんにちは!新井です。私の 2 本目のブログとなります!
デビュー作は以下です!
突然の宣伝でした、さっそく本題です。
目次
今回は、画像データを扱うために多くの方が使用するであろう、「OpenCV」 についてまとめました。
誰のための記事?
今回は初学者もサクッと入門できるように、Google Colaboratory だけで解説を行います。
ローカルでも同様の処理ができますので、「こんな使い方ができるんだ!」を体感していただけると幸いです。
OpenCV は、画像処理やコンピュータビジョンの領域で使用されるライブラリです。
コンピュータビジョンとは、カメラやセンサー情報を画像処理として扱う分野です。
画像処理検定というものがあるので、気になる方はチェックしてみてください。ディジタル画像処理という書籍の内容が鍵となると思います。
Pillow も聞いたことはあるけど、どんなものだっけ?
Pillow については以下で詳しく解説しているので、こちらもご覧ください!
機械学習で「画像処理」を学ぶための手前の段階で出会うと思われる 2 つのライブラリですが、ここでどのような違いがあるのかを把握しておきましょう。
大きな違いとして、画像情報は RGB と記憶する方が多いと思いますが、Pillow は RGB、OpenCV は BGR と、チャンネルの順序が異なります。実装時に注意したい点です。
Pillow | OpenCV | |
|---|---|---|
特徴 | 画像の基本的な処理に向いている | 画像の基本的な処理から複雑な変換などに向いている。 |
難易度 | 簡単 | 中から難しいレベルまである |
メリット | 初心者向け、画像のリサイズや保存が簡単 | 画像の変換が Pillow よりも豊富、特徴量抽出可能、機械学習に匹敵する機能あり |
デメリット | 画像に対して高度な変換できない、特徴量を抽出できない | 難易度が高い画像変換を行う場合、一筋縄ではいかない場面が多い |
比較表
今回は Google Colaboratory を使用するということで、変換した画像は matplotlib で表示させ、変換後の画像を確認する方針ですすめます。
Pillow 編では拡張子「png」を使用しました。今回はオリジナル画像を使用するために拡張子「jpg」を使用します。
ここでは「png」から「jpg」の変換コードを紹介します。なお、解説は割愛します。
import cv2 import matplotlib.pyplot as plt # png 画像の読み込み sample_img_png = cv2.imread('sample.png') # 画像の拡張子を変更 png → jpg cv2.imwrite('sample_img_jpg.jpg', sample_img_png) # 画像の表示→ matplotlib では cv2.COLOR_BGR2RGB の設定が必要 sample_img_jpg = cv2.imread('sample_img_jpg.jpg') plt.imshow(cv2.cvtColor(sample_img_jpg, cv2.COLOR_BGR2RGB)) plt.show()
import cv2 import matplotlib.pyplot as plt # 画像の読み込み img = cv2.imread('chaco.jpg') # 画像の確認 plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.show()
私のオリジナル画像で動作確認をしたキャプチャです。チャコ氏といううさぎなのですが、この画像は表示されているメモリからすると、高さ約 4000 、幅約 3000 の画像です。食べているのは草です。

画像の準備、画像の表示ができれば Google Colaboratory を用意すると、ここから先、 OpenCV の体験ができます!
早速やっていきましょう!
すべての画像を同じ大きさにリサイズする場合、簡単にリサイズできる方法です。
# モジュールの読み込み import cv2 import matplotlib.pyplot as plt # 画像の読み込み img = cv2.imread('chaco.jpg') # 画像のサイズを 1000 ✕ 1000 に変換 resize_img_1 = cv2.resize(img, dsize=(1000, 1000)) # 画像の確認 plt.imshow(cv2.cvtColor(resize_img_1, cv2.COLOR_BGR2RGB)) plt.show()
少々顔がつぶれたチャコ氏になりました。
画像によっては、このように少々変な画像変換となることもあります。

画像の読み込みを省略したコードです。
# 画像のサイズを縦横 1/10 のサイズに変換 img = cv2.resize(img, dsize=None, fx=0.1 , fy=0.1) # 画像の確認 plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.show()
こちらはリサイズ 1 とは異なり、高さと幅の比率を維持しているので、違和感のないリサイズができます。

今回は 90 度、時計回りへ画像を回転させます。
# 回転 img_rotate = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 画像の確認 plt.imshow(cv2.cvtColor(img_rotate, cv2.COLOR_BGR2RGB)) plt.show()
回転しても可愛いチャコ氏です。
単に 1 枚の画像を回転させるだけならば、PC の画像ソフトなどで変換したほうが早いかもしれません。
しかし、大量の画像を回転させたい場合はコード実行すると作業が楽になります。
また、機械学習で画像データを学習させる際、回転させた画像を学習に使用することもできます(例外あり)。工場部品のネジを思い浮かべていただくと、見る方向によってネジの向きが変わると思います。かといって、色んな角度の画像を生成して学習させるか?というとそうではないので、データが少なくて学習データが不足している際に使える一つの策だと思ってください。

機械学習での画像変換で使用率が高いと思われる処理です。
変換は簡潔なコードですが、matplotlib の仕様上、表示するコードは独特です。
# グレースケール変換 img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 画像の確認 plt.imshow(img_gray, cmap='gray') plt.show()
しっかりモノクロ画像になりました。

Pillow 編で紹介しているので、OpenCV でも紹介です。
# キカガクのロゴの読み込み(png でも合成できます) kikagaku_icon = cv2.imread('icon.png') # キカガクのロゴをチャコ氏の画像サイズに合わせる # kikagaku_icon.shape でサイズを取得できる→(302, 403)でした kihkagaku_icon =cv2.resize(kikagaku_icon, (302, 403)) # 画像を合成(引数の詳細は公式ドキュメントを参考に変更してください) blended = cv2.addWeighted(src1=img, alpha=0.7, src2=kihkagaku_icon, beta=0.3, gamma=0) # 画像の確認 plt.imshow(cv2.cvtColor(blended, cv2.COLOR_BGR2RGB)) plt.show()
画像を合成することができました。

画像の上下を反転させたい場面で使用できます。機械学習で画像処理を行う際にデータ水増しの一つの手段として使用できるケースがあります。
img_flip_ud = cv2.flip(img, 0) # 画像の確認 plt.imshow(cv2.cvtColor(img_flip_ud, cv2.COLOR_BGR2RGB)) plt.show()
チャコ氏の場合、上下反転させても「うさぎ」であることには変わりません。たまたま仰向けに寝ていて、上下反転していることもあるかもしれません。
「信号機」の場合はどうでしょうか?北海道など積雪対策された縦信号は例外として、信号機が上下反転することはないかと思います。この変換を使用する場合、逆転させて問題ないか?は確認しておきたいポイントです。

こちらも上下反転と同様に、左右逆転したい画像への変換、データの水増しに使用できる変換です。
# 左右反転 sample_img_jpg = cv2.imread('sample_img_jpg.jpg') img_flip_lr = cv2.flip(sample_img_jpg, 1) # 画像の確認 plt.imshow(cv2.cvtColor(img_flip_lr, cv2.COLOR_BGR2RGB)) plt.show()
まるで鏡のように左右が反転しているのが、「草の向き」からわかります。
このケース、データの水増しをする際に注意が必要です。
私はチャコ氏に詳しく、みなさんよりチャコ氏のドメイン知識があります。左右逆転すると、正確にはチャコ氏ではなくなってしまいます。しかし、「うさぎ」であることには変わらないと思います。この様に左右逆転するとよくないケースもあるので抑えておくポイントではあります。
余談ですが、最近では「あえて」左右逆転して撮影するカメラアプリもあるようです。芸能人の Instagram などで、もしかしたらみなさん、左右逆転した画像を見ているかもしれません。

二値化とは、画像を白と黒に変換することなのですが、次のコードでは、閾値を設定して白と黒に変換しています。今回は125 を閾値としていますが、お手元でこの閾値を調節してみてください。ただのグレースケール変換では見つからないような特徴が見つかるかもしれません。
# 閾値の設定 threshold = 125 # 二値化(閾値 125 を超えた画素を255にする。) ret, img_thresh = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY) # 画像の確認 plt.imshow(cv2.cvtColor(img_thresh, cv2.COLOR_BGR2GRAY), cmap='gray') plt.show()

次は使用する画像をテレビのリモコンにしてみました。画像のエッジ検出では、画像の中の物体のエッジ(特徴)を検出することを言います。これは実際に画像を見てどのような検出がされるのか?を見るとわかりやすいと思います。
輪郭やエッジを検出して物体検出や物体認識の前処理で利用されます。
このリモコンの画像からエッジを検出します。どこが特徴として検出されるのでしょうか?

import numpy as np # 画像の読み込み img_f = cv2.imread('remote_control.jpg') # グレースケール画像を用意 img_gray = cv2.cvtColor(img_f, cv2.COLOR_BGR2GRAY) # Sobel フィルタを適用してエッジを検出 sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3) # sobel_x と sobel_y を絶対値に変換してから合成する sobel_combined = cv2.addWeighted(np.absolute(sobel_x), 0.5, np.absolute(sobel_y), 0.5, 0) # 画像の確認 plt.imshow(sobel_combined, cmap='gray') plt.show()
検出結果です。リモコンの「ボタン」の部分が白く見える箇所があるかと思います。このリモコンの画像では、「ボタン」の部分に特徴があると認識されているようです。機械学習を使用しなくても OpenCV だけでここまでエッジを検出することもできます。

エッジ検出で、画像内の物体から特徴を検出できることがわかりました。OpenCV には他にも、特徴を検出する手法があります。その一部を紹介します。なお、おまけコードなので、解説は割愛します。
今回もエッジ検出と同じ、リモコンの画像から特徴を検出します。
import numpy as np # 画像の読み込み img_f = cv2.imread('remote_control.jpg') # グレースケール画像を用意 img_gray = cv2.cvtColor(img_f, cv2.COLOR_BGR2GRAY) gray = np.float32(img_gray) img_dst = np.copy(gray) dst = cv2.cornerHarris(gray, 2, 3, 0.05, img_dst) dst = cv2.dilate(dst,None,iterations = 3) img_f[dst>0.05*dst.max()]=[0, 0, 255] # 画像の確認 plt.imshow(cv2.cvtColor(img_f, cv2.COLOR_BGR2RGB)) plt.show()

2 枚の画像間で特徴量が一致している部分を確認することができます。
# 2つの画像を読み込む img1 = cv2.imread('an_old.jpg') img2 = cv2.imread('an.jpg') # 特徴点検出 akaze = cv2.AKAZE_create() kp1, des1 = akaze.detectAndCompute(img1, None) kp2, des2 = akaze.detectAndCompute(img2, None) # マッチング bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) matches = bf.match(des1, des2) # 特徴点間のハミング距離でソート matches = sorted(matches, key=lambda x: x.distance) # 2 つの画像のマッチング結果を作成、最も似ている 5 箇所を表示する img1_2 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:5], None) # 画像を確認 plt.imshow(cv2.cvtColor(img1_2, cv2.COLOR_BGR2RGB)) plt.title('Feature Matching Result') plt.axis('off') plt.show()
同じ人物で特徴量を検出した結果です。画像に表示されている直線は特徴が一致していることを表しています。5 本あるのですが、コード上で最もよく似た部分を 5 箇所だけ検出するようにしています。
どうやって似た特徴を抽出しているのかというと、2 つの画像の人物の「距離」で似ているかどうか(マッチングしているか)を検出しています。よく「〇〇に似ている人」のような会話を聞いたりする方もいると思いますが、これを使えば、どのくらい似ているか?の数値化まで行うことも可能です。

文字通り、画像内の物体の輪郭を抽出します。今回はわかりやすい例として、キカガクのロゴを使用します。
こちらがキカガクのロゴです。人間の目から見ても、なんとなく輪郭を見つけられそうですね。

# キカガクのロゴを読み込み kikagaku = cv2.imread('logo.jpg') # グレースケール変換 img_gray = cv2.cvtColor(kikagaku, cv2.COLOR_BGR2GRAY) # 輪郭を抽出するための設定 ret,thresh = cv2.threshold(img_gray,150,255,0) contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cnt_img = np.zeros_like(thresh, dtype=np.uint8) cnt_img = cv2.drawContours(cnt_img, contours, -1, 255, 2) # 画像の確認 plt.imshow(cnt_img,cmap='gray') plt.show()
コード内に「輪郭を抽出するための設定」という部分がありますが、ここで画像のどの部分を基準に輪郭を抽出するかを指定しています。ここは適宜値を変更してみてください。
今回は以下のように輪郭抽出されました。ロゴの一部が抽出されていない結果となりましたが、「文字」の部分まで輪郭が抽出されていることがわかります。

実は OpenCV で画像から顔を検出することができます。これを使用することで、機械学習を使用しなくても OpenCV とルールベースで画像分類などを実現することもできます。実は OpenCV は他にも色々な機能を持ち合わせているので、画像処理を今後行う方は OpenCV を使用する機会が増えると思います。困ったときに OpenCV で解決できないかな?を検討するのはかなり有効的だと個人的に思います。
どのように顔の検出ができるかを見ていきましょう。
今回、Google Colaboratory で顔検出を実現するには少々手順が増えます。
顔検出する際に OpenCV 提供しているファイルをダウンロードして、Google Colaboratory で読み込む必要があります。
まず、OpenCV の GitHub ページより data > haarcascades > haarcascade_frontalface_default.xml をダウンロードします。これは顔を検出するための「分類情報」を持っているファイルです。こちらをダウンロードし、Google Colaboratory へアップロードしてから以下のコードを実行すると、顔検出することができます。
# 顔検出したい画像の読み込み kikagaku_member = cv2.imread('/content/drive/MyDrive/キカガクブログ/2022_kikagaku.jpg') # RGB 変換 img = cv2.cvtColor(kikagaku_member, cv2.COLOR_BGR2RGB) # 事前にアップロードしたファイル読み込み cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml') # 顔を検出 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) face = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(30, 30)) # 検出した領域を矩形で囲む for (x, y, w, h) in face: cv2.rectangle(img, (x, y), (x + w, y + h), (200,0,0), 3) # 画像の確認 plt.imshow(img)
今回は、キカガクメンバーの写真を使用しました。
こちらを見ていただくとかなりの精度で顔の検出ができていることがわかるかと思います。
素敵な笑顔が検出されました (*^^*)

OpenCV でできること、イメージが湧きましたでしょうか?また、Pillow と異なる点について、この記事で少しでも理解が深まったら嬉しい限りです。
今回紹介したコードは OpenCV の一部の機能のみとなります。この記事で紹介した以外にも便利な機能がありますので、ぜひ調べて使ってみてください。
詳細は、公式ドキュメントや参考書などで学ぶのがおすすめです。
公式ドキュメントはやや癖がある(個人的感想)ので、一緒にトライしていきましょう!!
OpenCV は「画像変換」だけではなく、機械学習の前処理にも使用できます。
そして、ルールベースと合わせることで機械学習と同じような処理を実現することが可能です。
今後、画像処理分野に入門する方はぜひ、 OpenCV をチェックしていきましょう。
.jpg&w=3840&q=75)
キカガクの長期コースはプログラミング経験ゼロの初学者が最先端技術を使いこなすAIエンジニアになるためのサポート体制が整っています!
実際に未経験からの転職・キャリアアップに続々と成功中です
まずは無料説明会で、キカガクのサポート体制を確認しにきてください!
説明会ではこんなことをお話します!
.png&w=3840&q=75)
AI・機械学習を学び始めるならまずはここから!経産省の Web サイトでも紹介されているわかりやすいと評判の Python&機械学習入門コースが無料で受けられます!
さらにステップアップした脱ブラックボックスコースや、IT パスポートをはじめとした資格取得を目指すコースもなんと無料です!
SHARE
AI/データサイエンス学びはじめの方におすすめの記事
コース一覧
注目記事
新着記事
目次