2013
11
07
11
07
OpenCV: 他人から見た顔と自分で見た顔の違いをプログラミングで
"人は相手の顔を見るとき、左右どちらかの半分しかほぼ見ていない。右利きの人の大半は相手の顔の左半面で印象を判断する"という研究結果があるのをブルーバックスの『単純な脳、複雑な私』を読んで知った。
http://www.amazon.co.jp/dp/4062578301
ここに二枚の画像がある。この二枚をパッと瞬間的に見て、それぞれ男女どちらに見えるだろう。

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.100.5720
上の画像が男性、下の画像が女性だと見えたなら、そう見えた人は"相手の顔の左半面で判断する傾向がある人"である。これら二枚の画像は実は男性の顔を半分、女性の顔半分を切り出して合成したもので、上と下ではそれが左右反転したという違いしかない。それでも性別の判断が一貫せずに反転したなら、それは顔の左右どちらか半面だけを見て相手の特徴を判断しているということである。
研究論文: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.100.5720
上記の研究を知って、個人的に腑に落ちることがあった。ぼくの目は奥二重なのだけど、たいていの人には二重だと認識されていない。相手から見てぼくの右半面にある目を見れば二重のしわは確認できる。しかし相手から見て左半面にある目のほうは、力を入れて目を開かない限りは目の上の脂肪で二重のしわが隠れていて一重に見える。二重だと認識されやすい目がある右半面のほうは、ほとんどの人に認識されていないということだろう。
『単純な脳、複雑な私』ではこれを踏まえて、自分を鏡で見る自分の顔と、相手が認識する自分の顔は印象が違うものだと述べている。なぜなら鏡は左右が反転するから、鏡に写る自分の左半面は、多くの人が意識しない右半面にすりかわっている。
以上から考えるに、おそらく見ていないほうの半面は、脳が勝手に鏡像をつくって補完しているんだろう。というわけで、OpenCVの顔認識を使って、多くの人が見る私、少数の人が見える私を生成してくれるプログラムを書いてみた。顔は左右対称に思えて、実は細部で非対称になっている。多くの人が見る私と、少数の人が見る私では少しばかり印象が違ってくる。
上段:オリジナル
中段:多くの人が見る私(左半面の折り返し)
下段;少数の人が見る私(右半面の折り返し)

元画像となるものはAT&T Laboratories Cambridgeの研究用素材を用いた。
http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
突貫で書いてリファクタリングもろくにしていないスクリプト。動作はPython 2.7, OpenCV 2.4.6で確認。
画像の加工にOpenCVを使うこともできるが、不慣れならPILを使ったほうが手っ取り早い。
http://opencv.jp/opencv-2svn/py/cookbook.html#getsubrect
http://www.amazon.co.jp/dp/4062578301
ここに二枚の画像がある。この二枚をパッと瞬間的に見て、それぞれ男女どちらに見えるだろう。

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.100.5720
上の画像が男性、下の画像が女性だと見えたなら、そう見えた人は"相手の顔の左半面で判断する傾向がある人"である。これら二枚の画像は実は男性の顔を半分、女性の顔半分を切り出して合成したもので、上と下ではそれが左右反転したという違いしかない。それでも性別の判断が一貫せずに反転したなら、それは顔の左右どちらか半面だけを見て相手の特徴を判断しているということである。
研究論文: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.100.5720
上記の研究を知って、個人的に腑に落ちることがあった。ぼくの目は奥二重なのだけど、たいていの人には二重だと認識されていない。相手から見てぼくの右半面にある目を見れば二重のしわは確認できる。しかし相手から見て左半面にある目のほうは、力を入れて目を開かない限りは目の上の脂肪で二重のしわが隠れていて一重に見える。二重だと認識されやすい目がある右半面のほうは、ほとんどの人に認識されていないということだろう。
『単純な脳、複雑な私』ではこれを踏まえて、自分を鏡で見る自分の顔と、相手が認識する自分の顔は印象が違うものだと述べている。なぜなら鏡は左右が反転するから、鏡に写る自分の左半面は、多くの人が意識しない右半面にすりかわっている。
以上から考えるに、おそらく見ていないほうの半面は、脳が勝手に鏡像をつくって補完しているんだろう。というわけで、OpenCVの顔認識を使って、多くの人が見る私、少数の人が見える私を生成してくれるプログラムを書いてみた。顔は左右対称に思えて、実は細部で非対称になっている。多くの人が見る私と、少数の人が見る私では少しばかり印象が違ってくる。
上段:オリジナル
中段:多くの人が見る私(左半面の折り返し)
下段;少数の人が見る私(右半面の折り返し)

元画像となるものはAT&T Laboratories Cambridgeの研究用素材を用いた。
http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
突貫で書いてリファクタリングもろくにしていないスクリプト。動作はPython 2.7, OpenCV 2.4.6で確認。
#!/usr/bin/env python
import exceptions
import numpy as np
import Image
import cv2
import cv2.cv as cv
help_message = '''
USAGE: facedetect.py [image file]
'''
def detect(img, cascade):
rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(5, 5), flags = cv.CV_HAAR_SCALE_IMAGE)
if len(rects) == 0:
return []
rects[:,2:] += rects[:,:2]
return rects
def draw_rects(img, rects, color):
for x1, y1, x2, y2 in rects:
cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
def getXCenterByEyes(rects):
if len(rects) != 2:
raise exceptions.ValueError("couldn't detect eyes")
if rects[0][0] < rects[1][0]:
rect1 = rects[0]
rect2 = rects[1]
else:
rect1 = rects[1]
rect2 = rects[0]
x1 = (rect1[2] + rect1[0]) * 0.5
x2 = (rect2[2] + rect2[0]) * 0.5
return int((x2 + x1) * 0.5)
def main():
import sys, getopt
print help_message
filename = sys.argv[1]
cascade_fn = "../../data/haarcascades/haarcascade_frontalface_alt.xml"
nested_fn = "../../data/haarcascades/haarcascade_eye.xml"
face_cascade = cv2.CascadeClassifier(cascade_fn)
eye_cascade = cv2.CascadeClassifier(nested_fn)
try:
image = cv.LoadImageM(filename)
except:
return
img = np.asarray(image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
im = cv.fromarray(img)
rects = detect(gray, face_cascade)
x0, y0, x1, y1 = rects[0]
print rects[0]
cv_face = cv.GetSubRect(im, (x0, y0, x1 - x0, y1 - y0))
im = cv.fromarray(cv_face)
gray = cv2.cvtColor(np.asarray(cv_face), cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
subrects = detect(gray, eye_cascade)
print subrects
center = getXCenterByEyes(subrects)
converted_color = cv2.cvtColor(np.asarray(im), cv.CV_BGR2RGB)
original_image = Image.fromstring("RGB", cv.GetSize(cv_face), converted_color.tostring())
for x in xrange(4):
center += 1
left_side = original_image.crop((0, 0, center, im.height))
new_image = Image.new("RGB", (center * 2, im.height))
new_image.paste(left_side, (0, 0, center, new_image.size[1]))
new_image.paste(left_side.transpose(Image.FLIP_LEFT_RIGHT), (center, 0, new_image.size[0], new_image.size[1]))
new_image.save(filename + "_major" + str(x) + ".jpg")
for x in xrange(4):
center -= 1
right_side = original_image.crop((center, 0, im.width, im.height))
new_image = Image.new("RGB", ((im.width - center) * 2, im.height))
new_image.paste(right_side, ((im.width - center), 0, new_image.size[0], new_image.size[1]))
new_image.paste(right_side.transpose(Image.FLIP_LEFT_RIGHT), (0, 0, im.width - center, new_image.size[1]))
new_image.save(filename + "_minor" + str(x) + ".jpg")
if __name__ == '__main__':
main()
画像の加工にOpenCVを使うこともできるが、不慣れならPILを使ったほうが手っ取り早い。
http://opencv.jp/opencv-2svn/py/cookbook.html#getsubrect
スポンサーサイト