OpenCVで画像・映像加工処理 画像や映像を好き勝手加工してみる パート2 ヒストグラムの作成とモザイク加工

  • HOME
  • SPI ブログ
  • OpenCVで画像・映像加工処理 画像や映像を好き勝手加工してみる パート2 ヒストグラムの作成とモザイク加工

画像や映像を好き勝手加工してみる パート2 ~ヒストグラムの作成とモザイク加工~

OpenCVで画像・映像加工処理

こんにちは。目指せ!脱コボラー!のsakaです。

前回に引き続き、Python×OpenCVで、画像や映像を加工してみた話です。
パート2では、ヒストグラムの作成とモザイク加工についてです。
具体的には、以下の4つを紹介します。

・ヒストグラム
・座標指定のモザイク
・顔モザイク,目モザイク
・Webカメラで目モザイク

前準備

・必要なモジュールを用意
matplotlib.pyplot
自動的に図形や軸を作成するインターフェース

・以下のコマンドを実行

pip install matplotlib

・フォルダ構造

/rgb/
  /facemosaic.py  ## new
  /gray.py
  /hist.py   ## new
  /mosaic.py  ## new
  /replace.py
  /rgb.py
  /webmosaic.py  ## new
  /img/
    /fruit.jpg
    /nicemans.png  ## new

この画像を加工していきます。

・ヒストグラム
(fruit.jpg)

・それ以外
(nicemans.png)

プログラム

・ヒストグラム
matplotlib.pyplotを使用

python:hist.py

import cv2
import numpy as np
import os
import matplotlib.pyplot as plt

PATH = './img'
FILES = os.listdir(PATH)
COLOR = ('b', 'g', 'r')

# get file name
def get_file_name():
	print('*** All  Pictures ***')
	print(*FILES, sep='\n')
	print('***      End      ***')
	
	while True:
		file_name = input('Which use file name ?: ')
		if file_name in FILES:
			return file_name
		else:
			print('not exist: ' + file_name)

if __name__ == '__main__':
	
	file_name = get_file_name()
	file_prefixes = file_name.rsplit('.', 1)
	simple_file_name = file_prefixes[0]
	
	# 元の画像を読み込む
	file_img = cv2.imread(PATH + '/'+ file_name, cv2.IMREAD_COLOR)

	# ウィンドウを作成
	cv2.namedWindow(simple_file_name)

	# ウィンドウに表示
	cv2.imshow(simple_file_name, file_img)
	
	for i, col in enumerate(COLOR):
		histr = cv2.calcHist([file_img], [i], None, [256], [0, 256])
		plt.plot(histr, color = col)
		plt.xlim([0,256])
	plt.show()

	# 終了処理
	cv2.waitKey(0)
	cv2.destroyAllWindows()

cv2.calcHistでヒストグラムを計算することができます。
赤系が多いため、ヒストグラムの赤線も右寄りになっています。

(hist.png)

・座標指定のモザイク
モザイクは指定した位置を縮小し、拡大で戻したものを使用している。

import cv2
import numpy as np
import os

PATH = './img'
FILES = os.listdir(PATH)

OLD_WINDOW_NAME = 'old'
NEW_WINDOW_NAME = 'new'

# モザイクの粗さ
ratio = 0.1

# get file name
def get_file_name():
	print('*** All  Pictures ***')
	print(*FILES, sep='\n')
	print('***      End      ***')
	
	while True:
		file_name = input('Which use file name ?: ')
		if file_name in FILES:
			return file_name
		else:
			print('not exist: ' + file_name)

def mosaic(src):
	small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
	return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

def mosaic_area(src, x, y, width, height):
	dst = src.copy()
	dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width])
	return dst

if __name__ == '__main__':
	
	old_file_name = get_file_name()
	file_prefixes = old_file_name.rsplit('.', 1)
	new_file_name = file_prefixes[0] + '_after.' + file_prefixes[1]

	# 元の画像を読み込む
	old_img = cv2.imread(PATH + '/'+ old_file_name)
	
	# モザイク化
	new_img = mosaic_area(old_img, 100, 50, 100, 150)
	
	# ウィンドウを作成
	cv2.namedWindow(OLD_WINDOW_NAME)
	cv2.namedWindow(NEW_WINDOW_NAME)

	# ウィンドウに表示
	cv2.imshow(OLD_WINDOW_NAME, old_img)
	cv2.imshow(NEW_WINDOW_NAME, new_img)

	# ファイルに保存
	cv2.imwrite(r'img/{}'.format(new_file_name), new_img)

	# 終了処理
	cv2.waitKey(0)
	cv2.destroyAllWindows()

ratioが小さければ小さいほど粗いモザイクが作成される。
(nicemans_mosaic.png)

・顔モザイク,目モザイク
顔の学習データ “[haarcascade_frontalface_alt.xml](https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_alt.xml)” を使用する。

python:facemosaic.py

import cv2
import numpy as np
import os

PATH = './img'
FILES = os.listdir(PATH)

FACE_CASCADE_PATH = "haarcascade_frontalface_alt.xml"
FACE_CASCADE = cv2.CascadeClassifier(FACE_CASCADE_PATH)

ratio = 0.05

# get file name
def get_file_name():
	print('*** All  Pictures ***')
	print(*FILES, sep='\n')
	print('***      End      ***')
	
	while True:
		file_name = input('Which use file name ?: ')
		if file_name in FILES:
			return file_name
		else:
			print('not exist: ' + file_name)

def mosaic(src):
	small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
	return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

def mosaic_area(src, x, y, width, height):
	dst = src.copy()
	dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width])
	return dst

if __name__ == '__main__':
	old_file_name = get_file_name()
	file_prefixes = old_file_name.rsplit('.', 1)
	new_file_name = file_prefixes[0] + '_after.' + file_prefixes[1]

	# 元の画像を読み込む
	old_img = cv2.imread(PATH + '/'+ old_file_name)
	new_img = np.copy(old_img)
	
	# グレイスケール,学習データ精査
	gray_frame = cv2.cvtColor(new_img, cv2.COLOR_RGB2GRAY)
	front_face_list = FACE_CASCADE.detectMultiScale(gray_frame, minSize = (50, 50), minNeighbors=5)
	
	# 認識された顔の数
	face_count = str(len(front_face_list))
	cv2.putText(new_img, face_count.zfill(3), (0,30), cv2.FONT_HERSHEY_PLAIN, 2, (0, 0, 0), 3, cv2.LINE_AA)

	# モザイク化
	for (x, y, w, h) in front_face_list:
		new_img = mosaic_area(new_img, x, y, w, h)
		
		cv2.rectangle(new_img, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)
		
	cv2.imshow('OldRawFrame', old_img)
	cv2.imshow('NewRawFrame', new_img)
	
	cv2.imwrite(r'img/{}'.format(new_file_name), new_img)

	# 終了処理
	cv2.waitKey(0)
	cv2.destroyAllWindows()

(nicemans_faces.png)

グレイスケールしたデータを学習データで精査し、顔を認識してくれます。
このように niceman が複数人いてもきちんと数えられている。
さらに修正して、目線にモザイクを付けるようにしてみた。

python:facemosaic.py


FACE_CASCADE_PATH = "haarcascade_frontalface_alt.xml"
FACE_CASCADE = cv2.CascadeClassifier(FACE_CASCADE_PATH)

# 追加
EYE_CASCADE_PATH = "haarcascade_eye.xml"
EYE_CASCADE = cv2.CascadeClassifier(EYE_CASCADE_PATH)


	# モザイク化
	for (x, y, w, h) in front_face_list:
		# new_frame = mosaic_area(new_frame, x, y, w, h) # 削除
		
		cv2.rectangle(new_img, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)

		# 追加
		eye_list = EYE_CASCADE.detectMultiScale(gray_frame, minNeighbors=40)

		for (ex, ey, ew, eh) in eye_list:
			if x < ex and y < ey and x + w > ex + ew and y + h > ey + eh:
				new_frame = mosaic_area(new_frame, x, ey, w, eh)

(nicemans_eyes.png)

目の学習データ [haarcascade_eye.xml](https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_eye.xml) を使用した

 EYE_CASCADE.detectMultiScale(gray_frame, minNeighbors=40)

minNeighbors=40にすることにより、誤検知を少なくする。
また、赤枠(顔検知)外で目と検知されたものも対象外となるようにした。

・Webカメラで目モザイク

python:webmosaic.py

import cv2

cap = cv2.VideoCapture(0)

face_cascade_path = "haarcascade_frontalface_alt.xml"
eye_cascade_path = "haarcascade_eye.xml"

face_cascade = cv2.CascadeClassifier(face_cascade_path)
eye_cascade = cv2.CascadeClassifier(eye_cascade_path)

if __name__ == '__main__':

	while True:
		ret, old_frame = cap.read()
		new_frame = old_frame.copy()
		
		gray_frame = cv2.cvtColor(new_frame, cv2.COLOR_RGB2GRAY)
		front_face_list = face_cascade.detectMultiScale(gray_frame, minSize = (50, 50), minNeighbors=3)
		face_count = str(len(front_face_list))
		cv2.putText(new_frame, face_count.zfill(3), (500,50), cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 5, cv2.LINE_AA)
		
		
		for (x, y, w, h) in front_face_list:
			eye_list = eye_cascade.detectMultiScale(gray_frame, minNeighbors=20)

			for (ex, ey, ew, eh) in eye_list:
				if x < ex and y < ey and x + w > ex + ew and y + h > ey + eh:
					cv2.rectangle(new_frame, (x+10, ey), (x + w-10, ey + eh), (0, 0, 0), thickness=-1)
			
			cv2.rectangle(new_frame, (x, y), (x + w, y + h), (0, 0, 255), thickness=3)
			
		cv2.imshow('OldRawFrame', old_frame)
		cv2.imshow('NewRawFrame', new_frame)
		
		k = cv2.waitKey(1)
		if k == 27:
			break
			
	cap.release()
	cv2.destroyAllWindows()

基本的にfacemosaic.pyと同じプログラムです。
cv2.VideoCaptureでデバイス番号0のカメラを起動して、処理を行なっている。
眼鏡や横顔などはまだ反応できないことがあるが、目モザイクを付けることができた!

まとめ

Webカメラを使用したモザイク加工をすることができた。
ラズパイなどに活用して、監視カメラや顔認証ができるのではないかと思いました。

また、動物やモノを学習データとしてinputさせてあげれば、それらを検知することができるのではないかと思いました。
良いデータが見つかればまた動かしてみようと思います。

以上です!

最新ブログ一覧