OpenCVで虹顔の識別(※ただし表情がとぼしくて可愛いおにゃのこに限る)すた2011年09月25日

このエントリーをはてなブックマークに追加
はてなブックマーク - OpenCVで虹顔の識別(※ただし表情がとぼしくて可愛いおにゃのこに限る)

はい、ちょっと***な諸事情で、画像中に全く同じ画像が含まれているかを調べる必要があったのですが、自力ではうまく行かず、
OpenCV使ったら一瞬で出来てしまって不覚にも感動してしまいました。
、という更新。

こんな紛らわしい画像(右側は微妙に口の形が違う)も「違う」と判断してくれてさすがです。

 

、何がしたかったのかというと、虹画像の表情を判断したかったわけで、
さらにその表情ごとの画像は一意に決まってるというまあなんともレアケース。

笑ってるときは画像01、泣いてるときは画像02、みたいに。
表情が乏しいとも言います、はい。

むすっとした顔の穹ちゃんはかわいいけどね!!

、これらの画像から、下のおにゃのこの表情が何なのかを調べてみますと、
    

まあよく分かりませんが「一番左の画像が完全に一致」、と判定してくれるわけです。
OpenCV便利すぎくそわろうた、です。

今回はなんとなくC#でOpenCvSharp使いました。
OpenCv:2.1
.NET:4.0
公式のサンプル引っ張ってきただけです、はい。

要なのはこの2行だけで、

Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);
Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);

MatchTemplateで各点の相関係数をdst_imgに、
MinMaxLocで相関係数の最大値と最小値とそれぞれの位置を取得できるみたいです。

相関係数が1に近いほど正の相関があるので1に近ければ近いほど、類似の画像が含まれているということになります。
相関係数が1のときは完全に一致。

似たような画像でも0.998とか高めの値が出たので今回はしきい値を0.999にしました、テキトウw

using System;
using System.Collections.Generic;
using System.Linq;
using OpenCvSharp;
using System.IO;

namespace CVSharpTest
{
    class Program
    {        
        static void Main(string[] args)
        {
            //templateフォルダ以下にテンプレート画像を入れておく。
            IEnumerable<string> tempFiles = Directory.EnumerateFiles("./template","*",SearchOption.TopDirectoryOnly);
            Dictionary<string, double> NCCPair = new Dictionary<string, double>();

            IplImage target = IplImage.FromFile("target.png",LoadMode.Unchanged);            
            IplImage template;
           
            foreach (string file in tempFiles)
            {                
                template = IplImage.FromFile(file, LoadMode.Unchanged);
                double ncc = GetNCCMax(target,template);

                //対象画像からテンプレート画像を検索して表示する
                TemplateMatch(target, template);
               
                NCCPair.Add(file, ncc);
                Console.WriteLine("{0}:{1}", file, ncc);
            }

            //「相関係数の最大値が一番高いもの」が一致画像の可能性が高い
            var result = NCCPair.OrderByDescending((val) => val.Value).First();
            Console.WriteLine("MAX:{0} {1}",result.Key,result.Value);
           
            return;
        }
       
        /// <summary>
        /// 相関係数の最大値を計算する
        /// </summary>
        private static double GetNCCMax(IplImage target, IplImage template)
        {
            IplImage dst_img;                        
            double min_val, max_val;
            CvPoint min_loc, max_loc;
            CvSize dst_size;

            dst_size = new CvSize(target.Width - template.Width + 1, target.Height - template.Height + 1);
            dst_img = Cv.CreateImage(dst_size, BitDepth.F32, 1);
            Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);
           
            //相関係数の最大値と最小値を取得
            Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);
           
            Cv.ReleaseImage(dst_img);

            //相関係数の最大値を返す
            return max_val;
        }

        /// <summary>
        /// 対象画像からテンプレート画像の位置を探す
        /// </summary>        
        private static double TemplateMatch(IplImage target, IplImage template, double limen=0.999)
        {
            IplImage dst_img;
            double min_val, max_val;
            CvPoint min_loc, max_loc;
            CvSize dst_size;

            dst_size = new CvSize(target.Width - template.Width + 1, target.Height - template.Height + 1);
            dst_img = Cv.CreateImage(dst_size, BitDepth.F32, 1);
            Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);

            Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);

            if (max_val > limen)            
                Cv.Rectangle(target, max_loc,new CvPoint(max_loc.X + template.Width, max_loc.Y +template.Height),new CvScalar(0,0,250),3);                
           
            Cv.NamedWindow("Image", WindowMode.AutoSize);
            Cv.NamedWindow("Image2", WindowMode.AutoSize);
            Cv.ShowImage("Image", target);
            Cv.ShowImage("Image2", template);

            Cv.WaitKey(0);
            Cv.DestroyWindow("Image");
            Cv.DestroyWindow("Image2");  
            Cv.ReleaseImage(dst_img);

            return max_val;
        }
    }
}

今回の本当の目的はちょっとぴーぴーぴーなことなので詳しくはまあアレなのですが、
OpenCVの便利さ、そして手軽さはすごいなあと。

このエントリーをはてなブックマークに追加
はてなブックマーク - OpenCVで虹顔の識別(※ただし表情がとぼしくて可愛いおにゃのこに限る)

関連する記事

Leave a Reply

Dansette