Symfoware

Symfowareについての考察blog

OpenCV を使用して、写真に特定の人物が写っているか判定する

FreeBSD 10 + OpenCV 2.4.9 + py-opencvで色々試しました。

FreeBSD + OpenCV 2.4.9 + py-opencvで顔認識
OpenCV 2.4.9 + py-opencvでキーポイントの検出
OpenCV 2.4.9 + py-opencvで特徴量を算出する
OpenCV 2.4.9 使用できるDetector,Extractor,Matcher
py-opencv 画像の一部を切り抜いて保存する


材料は揃ったので、ちょっと実用的なテーマを。
写真に特定の人物が写っているか判定してみようと思います。



探す人



http://www.pakutaso.com/
大川竜弥さんを見つけることにしました。

サンプル画像は上記サイトからお借りしています。



比較用の画像



まず、大川さんが写っている写真を適当にピックアップ。

495_01.png


顔の輪郭を繰り抜き、白黒画像で保存しておきます。


  1. # -*- coding:utf-8 -*-
  2. import numpy
  3. import cv2
  4. cascade_path = '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
  5. for i in xrange(1, 11):
  6.     filename = "%02d.jpg" % i
  7.     
  8.     #ファイル読み込み
  9.     image = cv2.imread(filename)
  10.     #グレースケール変換
  11.     image_gray = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY)
  12.     #カスケード分類器の特徴量を取得する
  13.     cascade = cv2.CascadeClassifier(cascade_path)
  14.     #物体認識(顔認識)の実行
  15.     facerect = cascade.detectMultiScale(
  16.                     image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
  17.     
  18.     print filename, len(facerect)
  19.     
  20.     if len(facerect) <= 0:
  21.         continue
  22.     
  23.     rect = facerect[0]
  24.     for r in facerect:
  25.         if rect[2] < r[2]:
  26.             rect = r
  27.         
  28.     
  29.     x = rect[0]
  30.     y = rect[1]
  31.     w = rect[2]
  32.     h = rect[3]
  33.     
  34.     # img[y: y + h, x: x + w]
  35.     cv2.imwrite('face_' + filename, image_gray[y:y+h, x:x+w])




いくつか顔認識に失敗してしまい、得られたのはこの8枚でした。

495_02.png


この画像と比較して、よく一致している場合は大川さんが写っていると
判定すれば良さそうです。







使用するアルゴリズム



よく一致しているの判定をどうすればよいか悩んだのですが、
マッチした中の最短距離を使用することにしました。
ここらへん、改善の余地ありだと思います。

使用するアルゴリズムは何が良いか、大川さんが写っているのと他の人が写っている写真で、
総当りで試して、写っているものが最小となる組み合わせを選んでみます。


  1. # -*- coding:utf-8 -*-
  2. import numpy
  3. import cv2
  4. def calc(detector_name, extractor_name, matcher_name, face_image,f):
  5.     
  6.     # キーポイントの検出
  7.     detector = cv2.FeatureDetector_create(detector_name)
  8.     keypoints1 = detector.detect(face_image)
  9.     #print 'in:kp:',len(keypoints1)
  10.     # 画像データの特徴量
  11.     descripter = cv2.DescriptorExtractor_create(extractor_name)
  12.     k1,d1 = descripter.compute(face_image, keypoints1)
  13.     # matcher準備
  14.     matcher = cv2.DescriptorMatcher_create(matcher_name)
  15.     
  16.     min_mean = 100000
  17.     
  18.     # テスト画像読み込み
  19.     for i in xrange(1, 9):
  20.         
  21.         # 画像はグレースケール変換済
  22.         test_file = "face_%02d.jpg" % i
  23.         test_image = cv2.imread(test_file)
  24.         
  25.         #print test_file
  26.         
  27.         # キーポイントの検出
  28.         keypoints2 = detector.detect(test_image)
  29.         #print len(keypoints2)
  30.         k2,d2 = descripter.compute(test_image, keypoints2)
  31.         # キーの一致度合いを調べる
  32.         try:
  33.             matches = matcher.match(d1, d2)
  34.         except:
  35.             continue
  36.         #print '#matches:', len(matches)
  37.         dist = [m.distance for m in matches]
  38.         
  39.         if len(dist) == 0:
  40.             continue
  41.         
  42.         #min_mean = min(min(dist), min_mean)
  43.         min_mean = min((sum(dist) / len(dist)), min_mean)
  44.         
  45.         #print 'distance: min: %.3f' % min(dist)
  46.         #print 'distance: mean: %.3f' % (sum(dist) / len(dist))
  47.         #print 'distance: max: %.3f' % max(dist)
  48.     
  49.         # threshold: half the mean
  50.         #thres_dist = (sum(dist) / len(dist)) * 0.5
  51.     
  52.         # keep only the reasonable matches
  53.         #sel_matches = [m for m in matches if m.distance < thres_dist]
  54.     
  55.         #print '#selected matches:', len(sel_matches)
  56.     
  57.     f.write('%d\t%s\t%s\t%s\t%d\n' % (len(keypoints1), detector_name, extractor_name, matcher_name, min_mean))
  58.     print len(keypoints1), detector_name, extractor_name, matcher_name, min_mean
  59.     
  60. cascade_path = '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
  61. filename = 'pic4.jpg'
  62. #ファイル読み込み
  63. image = cv2.imread(filename)
  64. #グレースケール変換
  65. image_gray = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY)
  66. #カスケード分類器の特徴量を取得する
  67. cascade = cv2.CascadeClassifier(cascade_path)
  68. #物体認識(顔認識)の実行
  69. facerect = cascade.detectMultiScale(
  70.                 image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
  71. if len(facerect) <= 0:
  72.     print u'not found!'
  73. rect = facerect[0]
  74. for r in facerect:
  75.     if rect[2] < r[2]:
  76.         rect = r
  77.     
  78. x = rect[0]
  79. y = rect[1]
  80. w = rect[2]
  81. h = rect[3]
  82. # img[y: y + h, x: x + w]
  83. face_image = image_gray[y:y+h, x:x+w]
  84. cv2.imwrite("detected.jpg", face_image)
  85. detectors = ['FAST','ORB','BRISK','MSER','GFTT','HARRIS','Dense']
  86. extractors = ['ORB','BRISK','BRIEF','FREAK']
  87. matchers = ['BruteForce','BruteForce-L1','BruteForce-SL2','BruteForce-Hamming','BruteForce-Hamming(2)']
  88. f = open('result4.txt', 'w')
  89. for detector in detectors:
  90.     for extractor in extractors:
  91.         for matcher in matchers:
  92.             calc(detector, extractor, matcher, face_image, f)
  93. f.close()




この結果
detector:Dense
extractor:BRISK
matcher_name:BruteForce-Hamming
の組み合わせがよさ気だったので、これを比較に使用することにします。




比較プログラム



距離の最小値が100未満なら大川さんが写っていると判定します。
こんな感じになりました。


  1. # -*- coding:utf-8 -*-
  2. import numpy
  3. import cv2
  4. def calc(detector_name, extractor_name, matcher_name, face_image):
  5.     
  6.     # キーポイントの検出
  7.     detector = cv2.FeatureDetector_create(detector_name)
  8.     keypoints1 = detector.detect(face_image)
  9.     # 画像データの特徴量
  10.     descripter = cv2.DescriptorExtractor_create(extractor_name)
  11.     k1,d1 = descripter.compute(face_image, keypoints1)
  12.     # matcher準備
  13.     matcher = cv2.DescriptorMatcher_create(matcher_name)
  14.     
  15.     min_dist = 100000
  16.     
  17.     # テスト画像読み込み
  18.     for i in xrange(1, 9):
  19.         
  20.         # 画像はグレースケール変換済
  21.         test_file = "face_%02d.jpg" % i
  22.         test_image = cv2.imread(test_file)
  23.         
  24.         #print test_file
  25.         
  26.         # キーポイントの検出
  27.         keypoints2 = detector.detect(test_image)
  28.         #print len(keypoints2)
  29.         k2,d2 = descripter.compute(test_image, keypoints2)
  30.         # キーの一致度合いを調べる
  31.         try:
  32.             matches = matcher.match(d1, d2)
  33.         except:
  34.             continue
  35.         #print '#matches:', len(matches)
  36.         dist = [m.distance for m in matches]
  37.         
  38.         if len(dist) == 0:
  39.             continue
  40.         
  41.         min_dist = min(min(dist), min_dist)
  42.     
  43.     return min_dist
  44.     
  45. cascade_path = '/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
  46. for i in xrange(1, 11):
  47.     filename = 'pic%d.jpg' % i
  48.     #ファイル読み込み
  49.     image = cv2.imread(filename)
  50.     #グレースケール変換
  51.     image_gray = cv2.cvtColor(image, cv2.cv.CV_BGR2GRAY)
  52.     #カスケード分類器の特徴量を取得する
  53.     cascade = cv2.CascadeClassifier(cascade_path)
  54.     #物体認識(顔認識)の実行
  55.     facerect = cascade.detectMultiScale(
  56.                     image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
  57.     if len(facerect) <= 0:
  58.         print u'not found!'
  59.     # 適当に一番大きそうな画像を探す
  60.     rect = facerect[0]
  61.     for r in facerect:
  62.         if rect[2] < r[2]:
  63.             rect = r
  64.         
  65.     x = rect[0]
  66.     y = rect[1]
  67.     w = rect[2]
  68.     h = rect[3]
  69.     # img[y: y + h, x: x + w]
  70.     face_image = image_gray[y:y+h, x:x+w]
  71.     cv2.imwrite("detected_" + filename, face_image)
  72.     resutl = calc('Dense', 'BRISK', 'BruteForce-Hamming', face_image)
  73.     if resutl < 100:
  74.         print filename, resutl, 'okawa'
  75.     else:
  76.         print filename, resutl, 'not okawa'




ピックアップで10枚写真を選び、プログラムを実行してみます。


pic1.jpg 97.0 okawa
pic2.jpg 110.0 not okawa
pic3.jpg 99.0 okawa
pic4.jpg 72.0 okawa
pic5.jpg 79.0 okawa
pic6.jpg 94.0 okawa
pic7.jpg 108.0 not okawa
pic8.jpg 112.0 not okawa
pic9.jpg 108.0 not okawa
pic10.jpg 108.0 not okawa





正答率は70%でした。適当に作った割にはよいスコアじゃないでしょうか。

495_03.png


認識精度の向上方法や、判定方法の改善が必要ですね。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2014/11/02(日) 18:24:44|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
<<OpenCV 写真に特定の人物が写っているか判定 その2 | ホーム | py-opencv 画像の一部を切り抜いて保存する>>

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://symfoware.blog68.fc2.com/tb.php/1525-263b73dc
この記事にトラックバックする(FC2ブログユーザー)