【OpenCV/Pil】Pythonの画像処理でできること11選!

今回はPythonで画像処理をしていきたいと思う。画像処理って画像編集ソフト使ってごちゃごちゃやったりするけど、プログラムの力でもできるからどんなことができるのか見ていこう。場合によっては画像編集ソフトを使うよりもプログラムでやる方が楽なものもあるかもしれない。

Pythonを使った画像処理11選

白黒/色変更

画像の色合いを変更してみよう。方法はいくつかあると思うけど、OpenCVを使って白黒の画像を作ってみる。こちらの画像を白黒にしてみよう。

白黒にする前の画像

コードはこんな感じで実行すると、白黒の画像になってくれる。

import cv2

# 画像を読み込み
im = cv2.imread('/Users/U/Downloads/dog2.jpg')
# OpenCvのcvtColor()
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 保存
cv2.imwrite('/Users/U/Downloads/grey-dog2.jpg', im_gray)

Pythonで白黒にした画像

OpenCvのimreadで画像を読み込んだ場合、色の順番がBGR(青、緑、赤)になる。普通はRGB(赤、緑、青)だからちょっと戸惑うかもしれない。それと、これはたまたまグレースケールでやったけど、cv2.COLOR_BGR2HSVを使ってHSV形式で画像を表示したりといったことができるぞ。

フィルタで色を変える

フィルタを作って画像の色を変えるようなこともできますね。

Pythonで青色のフィルタをかけた画像 Pythonで赤色のフィルタをかけた画像

フィルタ画像を新しく作ってそれを元の画像に合成するっていうことをコードでやればできる。

import cv2
import numpy as np

im = cv2.imread('/Users/U/Downloads/dog2.jpg')
filter = np.zeros(im.shape[:3], dtype=np.uint8)
filter[:] = (255,100,100)
new_img = cv2.addWeighted(im,0.7, filter, 0.3, 0)
cv2.imwrite('/Users/U/Downloads/dog5.jpg', new_img)

cv2.addWeughted()っていうので作成したフィルタと元の画像を合成している。cv2.addWeighted(画像, alpha, フィルタ画像, beta, gamma)っていう感じでやったけど、フィルタ画像じゃなくて普通に画像を指定してやれば画像同士の合成もできます。むしろそっちが普通の使い方な気がする。

特定の色の部分を別の色に変える

色の範囲を指定して、その指定した範囲の色を特定の色に変更するっていうこともできる。

import cv2
import numpy as np

im = cv2.imread('/Users/U/Downloads/dog2.jpg')
hsv=cv2.cvtColor(im,cv2.COLOR_BGR2HSV)

lo=np.array([30,0,0])
hi=np.array([150,255,255])
mask=cv2.inRange(hsv,lo, hi)

im[mask>0]=(255,255,255)
cv2.imwrite('/Users/U/Downloads/dog3.jpg', im)

さっきの犬の画像の背景を白に変えてみたけど、これなかなか難しいですね。色の下限と上限を指定してその色を変更している(コードではマスク)けど、結構ムラが出る。

変更前の画像Pythonで背景を白色に変更した画像

この色コード!っていうドンピシャでその色を変更するには良さそうだけど、この赤い部分を変えたい・・・!ってなった時は難しそう。赤色にも種類があって、BGRなら単純な(0, 0, 255)だけじゃないだろうからね。こういうことやるのはPhotoshopなんかでやっちゃった方が楽だな。

明るさ・コントラストを変更する

次は明るさを変えてみよう。ImageEnhanceっていうやつを使ってコントラストを変えるコードを書いてみる。

from PIL import Image, ImageEnhance

im = Image.open('/Users/U/Downloads/cat.jpg')
brightnessEnhancer = ImageEnhance.Contrast(im)
new_img = brightnessEnhancer.enhance(1.5)
new_img.save('/Users/U/Downloads/new_cat.jpg', quality=95)  

色変えたりした時にはcv2をimportしていたけど、今度はPILからImageEnhanceっていうものを使ってコントラストを変える。実行するとこんな感じで結構変わるね。

明るさ・コントラストを変更する前の画像Pythonでコントラストを変更した画像

これはコントラストを変えてみたけど、明るさをImageEnhance.Brightness()を使ってあげてみるとこんな感じで明るくなる。

Pythonで明るさを変更した画像

これは簡単でいいね。いちいち画像編集のソフト開いて明るさあげてってやったりするの面倒だから、大雑把だけでコードでやってしまってもいいかもしれない。

線画

OpenCvを使って画像を線画にしてやろうと思うんだけど、線画を作るっていう機能自体はどうやらないみたいですね。だけど色々ごちゃごちゃいじって線画にできるようだから線画にしてみる。この画像を線画にしてみよう。

線画にする前の画像

コードはこれを実行してみると・・・

import cv2
import numpy as np

gray = cv2.imread('/Users/U/Downloads/shue.jpg', cv2.IMREAD_GRAYSCALE)
neiborhood24 = np.array([[1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1]],
  np.uint8
)
dilated = cv2.dilate(gray, neiborhood24, iterations=1)
diff = cv2.absdiff(dilated, gray)
contour = 255 - diff
cv2.imwrite("/Users/U/Downloads/shue2.jpg", contour)

Pythonで線画にしてみた画像

線画になりましたね。カラー画像から線画を作る[OpenCV & python]を参考にしてみたけど、写真っていうよりもイラストの方が綺麗になりそうですね。線がはっきりしている方が良さそう。

トリミング

画像をトリミングしてみたいんだけど、この蝶々の部分だけを切り出したい。

トリミングする前の画像

トリミング自体はシンプルなコードでいける。以下のコードを実行すると蝶々の部分だけが良い感じに切り取られるね。

from PIL import Image

im = Image.open('/Users/U/Downloads/chocho.jpg')
im.crop((200, 50, 500, 300)).save('/Users/U/Downloads/chocho-cropped.jpg', quality=95)

pythonでトリミングした画像

cropの引数で切り取る範囲をしているんだけど、これは画像によって切り取る範囲が決まっているからなかなか難しいですよね。画像見ながらトリミングの座標調整しないといけないからちょっと面倒。普通に画像編集ソフト使ってトリミングした方がトリミングだけなら楽だな。

塗りつぶし

画像の一部分を塗りつぶしたい時もあるでしょう。これはフィルターを作った時にフィルターの画像と元画像を合成するっていう手法を取ったけど、同じ方法でいけそうですね。ただOpenCvにrectangleっていう関数があるからこれを使ってやってみよう。

import cv2
import numpy as np

im = cv2.imread('/Users/U/Downloads/dog2.jpg')
cv2.rectangle(im, (200, 300), (500, 200), (0, 255, 0), thickness=-1)
cv2.imwrite('/Users/U/Downloads/rectngle.jpg', im)

pythonで塗りつぶした画像

OpenCVの描画機能を見てみると、OpenCvにはcv2.line()cv2.circle() , cv2.rectangle()cv2.ellipse()cv2.putText()などの関数があるから図形で塗りつぶすならその図形の関数を使えば良さそうです。

モザイク

画像にモザイクをかけるっていうっていうのはこっちでもやりましたね。OpenCVを使えば割と簡単にできる。

例えば、人物の顔画像にモザイクをかけてみる。

モザイクをかける前の画像

import cv2
 
face_cascade = cv2.CascadeClassifier('/Users/U/Downloads/haarcascade_frontalface_default.xml') 
src = cv2.imread('/Users/U/Downloads/face2.jpg')
img_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(img_gray)
 
for (x, y, w, h) in faces:
    small = cv2.resize(src[y:y+h, x:x+w], None, fx=0.01, fy=0.01, interpolation=cv2.INTER_NEAREST)
    src[y:y+h, x:x+w] = cv2.resize(small, (w, h), interpolation=cv2.INTER_NEAREST)

cv2.imwrite("/Users/U/Downloads/output.png", src)

これを実行すると顔の部分を認識して、その部分にモザイクをかけてくれる。

Pythonでモザイクをかけた画像

OpenCVの分類器を使って顔を認識しているんだけど、これはGithubから見ることができる。モザイク自体は画像をリサイズして作るっていうことをしているよ。

文字入れ

もちろん文字を入れることもできますよね。Python Pillow - 画像に重ねて文字を描くを参考にしてやってみよう。

from PIL import Image, ImageDraw, ImageFont

text = 'いっっっっっぬ!!!'
img = Image.open('/Users/U/Downloads/dog2.jpg')
imagesize = img.size 
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("/Users/U/Library/Fonts/HackGen-Bold.ttf", 64) 
size = font.getsize(text)
draw.text((100, 300), text, font=font, fill='#FFF')
img.save('/Users/U/Downloads/out.png', 'PNG', quality=100, optimize=True)

これを実行すると指定した文字が画像の中に入る。

Pythonで文字を入れた画像

フォントは自分のパソコンに入っているパスを指定すればOK。ちなみに今回使ったのは、白源っていうフォントでRicty を神フォントだと崇める僕が、フリーライセンスのプログラミングフォント「白源」を作った話に詳しく載っているぞ。

ぼかし

画像をぼかすのはopencvのフィルターを使えば簡単ですね。画像を読み込んでcv2.GaussianBlur()で画像ぼぼやけさせることができる。gaussianってぼかす時によく使いますよね。

import cv2
 
img = cv2.imread('/Users/U/Downloads/dog2.jpg')
blured = cv2.GaussianBlur(img, (15, 15), 3)
cv2.imwrite('/Users/U/Downloads/dog2-blured.jpg', blured)

Pythonでぼかしを入れた画像

ただこれGaussianBlurのドキュメント見ても引数なに指定すればいいのかよくわからないんだよな・・単語が難しい・・・

物体検出

これはさっきモザイクをかける時にやったような方法でできるけど、今回は猫を検出するようなコードを書いていきたい。OpenCVを使うんだけど、検出するための分類器。OpenCVで猫検出 (モデル配布)という記事があったので、ありがたく使わせていただきます。猫の画像を指定して実行しよう。

import sys
import cv2 as cv

def detect(imagefilename, cascadefilename):
    srcimg = cv.imread(imagefilename)
    if srcimg is None:
        print('cannot load image')
        sys.exit(-1)
    dstimg = srcimg.copy()
    cascade = cv.CascadeClassifier(cascadefilename)
    if cascade.empty():
        print('cannnot load cascade file')
        sys.exit(-1)
    objects = cascade.detectMultiScale(srcimg, 1.1, 3)
    for (x, y, w, h) in objects:
        print(x, y, w, h)
        cv.rectangle(dstimg, (x, y), (x + w, y + h), (0, 0, 255), 2)
    return dstimg

if __name__ == '__main__':
    result = detect('/Users/U/Downloads/cats.jpg', '/Users/U/Downloads/cascade.xml')
    cv.imwrite('/Users/U/Downloads/result.jpg', result)

これを実行するとこんな風に猫の顔が四角く囲われますね。

Pythonで物体検出をした画像

PythonっていうよりOpenCVだけどこういうの面白いよね。画像の中から何かを判別する分類器があれば、いろんなものを検出できそうです。

まとめ

Pythonでできる画像処理っていうことでいくつか見てみたけどどうだろうか。結構いろんなことができるけど、なんかPythonっていうよりOpenCVっていう感じが否めない。まあいいだろう・・・

フィルタつけたりぼかしたりっていうのはもしかしたらプログラムでやってしまった方が画像編集ソフトでやるより楽かもしれない。物体検出してその部分をぼかす、モザイクかけるっていうこともできたりして便利。