人臉偵測其實很常見,一般的相機,手機的相機APP 都支援人臉偵測,在拍照時可以以偵測
到的人臉做為對焦區域,Face Detect基本上就是找出人臉所在的位置,本篇所使用的原理
請參考這一篇 , 在opencv中有己經訓練好的檔案可以使用,常見包含人臉偵測,雙眼偵
測,以本篇來說只要換一下訓練的檔案,程式不用改一個字,就可以改成偵測雙眼的功能。
人臉偵測和人臉識別是2個不同的東西,就好比我看到人(偵測)以及我認識這個人(識
別),是二個不同層面的事情,當然你要識出這個人之前你要先看到這個人的人臉。
程式流程如下:
取得WebCam畫面 -> 轉成灰階 ->偵測人臉位置 ->把人臉標記在WebCam畫面上 ->顯
示 -> 重頭來過
package javacv2; import java.io.File; import java.net.URL; import org.bytedeco.javacpp.Loader; import static org.bytedeco.javacpp.helper.opencv_objdetect.cvHaarDetectObjects; import static org.bytedeco.javacpp.opencv_core.CV_AA; import org.bytedeco.javacpp.opencv_core.CvMemStorage; import org.bytedeco.javacpp.opencv_core.CvRect; import org.bytedeco.javacpp.opencv_core.CvScalar; import org.bytedeco.javacpp.opencv_core.CvSeq; import static org.bytedeco.javacpp.opencv_core.IPL_DEPTH_8U; import org.bytedeco.javacpp.opencv_core.IplImage; import static org.bytedeco.javacpp.opencv_core.cvClearMemStorage; import static org.bytedeco.javacpp.opencv_core.cvGetSeqElem; import static org.bytedeco.javacpp.opencv_core.cvLoad; import static org.bytedeco.javacpp.opencv_core.cvPoint; import static org.bytedeco.javacpp.opencv_core.cvRectangle; import static org.bytedeco.javacpp.opencv_imgproc.CV_BGR2GRAY; import static org.bytedeco.javacpp.opencv_imgproc.cvCvtColor; import org.bytedeco.javacpp.opencv_objdetect; import static org.bytedeco.javacpp.opencv_objdetect.CV_HAAR_DO_CANNY_PRUNING; import org.bytedeco.javacpp.opencv_objdetect.CvHaarClassifierCascade; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.OpenCVFrameGrabber; public class JavaCV2 { public static void main(String args[]) { //用 FrameGrabber 取得 得webcam FrameGrabber grabber = new OpenCVFrameGrabber(""); //宣告一個CanvasFrame ,就把它當作是一個JFrame用。 CanvasFrame canvas = new CanvasFrame("Webcam", CanvasFrame.getDefaultGamma() / grabber.getGamma()); //設定這一個JFrame關閉時順便把程式結束。 canvas.setDefaultCloseOperation( javax.swing.JFrame.EXIT_ON_CLOSE); try { //從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題) URL url = new URL("https://raw.github.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_frontalface_alt.xml"); //把網頁上取回來的資料寫入本地端檔案 File file = Loader.extractResource(url, null, "classifier", ".xml"); //假如有相同檔名己存在則刪除舊友的 file.deleteOnExit(); //指定classifier檔案名稱(也就是剛才由網路上捉下來的檔案路徑) String classifierName = file.getAbsolutePath(); // 預先載入 opencv_objdetect module . Loader.load(opencv_objdetect.class); //初始化HaarClassifierCascade CvHaarClassifierCascade classifier = new CvHaarClassifierCascade(cvLoad(classifierName)); //假如載入HaarClassifierCascade 失敗則結束程式 if (classifier.isNull()) { System.err.println("Error loading classifier file \"" + classifierName + "\"."); System.exit(1); } //啟動WebCam grabber.start(); //定義一個IplImage 存放取出來的影像 IplImage img; //先取一張畫面放入IplImage img = grabber.grab(); //取得影像的長寬 int width = img.width(); int height = img.height(); //建立一個灰階影像(用IPL_DEPTH_8U 原因為,灰階影像每一個pixel R,G,B值皆相等,只需要存一份即可) IplImage grayImage = IplImage.create(width, height, IPL_DEPTH_8U, 1); //建立一個CvMemStorage做運算用 CvMemStorage storage = CvMemStorage.create(); //設定顯示用的CanvasFrame為取出的影像大小 canvas.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight()); while (canvas.isVisible() && (img = grabber.grab()) != null) { //重置運算用的CvMemStorage cvClearMemStorage(storage); // 把原始影像變成灰階 cvCvtColor(img, grayImage, CV_BGR2GRAY); //偵測人臉 CvSeq faces = cvHaarDetectObjects(grayImage, classifier, storage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING); //取得捉到的人臉 int total = faces.total(); //在人臉上畫一個紅色的矩型 for (int i = 0; i < total; i++) { CvRect r = new CvRect(cvGetSeqElem(faces, i)); int x = r.x(), y = r.y(), w = r.width(), h = r.height(); cvRectangle(img, cvPoint(x, y), cvPoint(x + w, y + h), CvScalar.RED, 1, CV_AA, 0); } //顯示圖片 canvas.showImage(img); } } catch(Exception e) { } } }
至於主要用來偵測的cvHaarDetectObjects 用法如下 -資料來源
cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade, CvMemStorage* storage, double scale_factor=1.1, int min_neighbors=3, int flags=0, CvSize min_size=cvSize(0,0) );
- image
- 被檢圖像
- cascade
- harr 分類器級聯的內部標識形式
- storage
- 用來存儲檢測到的一序列候選目標矩形框的記憶體區域。
- scale_factor
- 在前後兩次相繼的掃描中,搜索視窗的比例繫數。例如1.1指將搜索視窗依次擴大10%。
- min_neighbors
- 構成檢測目標的相鄰矩形的最小個數(預設-1)。如果組成檢測目標的小矩形的個數和小於min_neighbors-1 都會被排除。如果min_neighbors 為 0, 則函數不做任何操作就返回所有的被檢候選矩形框,這種設定值一般用在用戶自定義對檢測結果的組合程式上。
- flags
- 操作方式。當前唯一可以定義的操作方式是 CV_HAAR_DO_CANNY_PRUNING。如果被設定,函數利用Canny邊緣檢測器來排除一些邊緣很少或者很多的圖像區域,因為這樣的區域一般不含被檢目標。人臉檢測中通過設定閾值使用了這種方法,並因此提高了檢測速度。
- min_size
- 檢測視窗的最小尺寸。預設的情況下被設為分類器訓練時採用的樣本尺寸(人臉檢測中預設大小是~20×20)。
接下來我們把程式中的
//從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題) URL url = new URL("https://raw.github.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_frontalface_alt.xml");
換成
//從網路上取得訓練好的檔案(不太建議用2.4版本的會有問題) URL url = new URL("https://raw.githubusercontent.com/Itseez/opencv/2.2/data/haarcascades/haarcascade_eye_tree_eyeglasses.xml");
網路上也有一些訓練好的檔案的資料可以使用,不限於只有人臉或雙眼,參考下列網址 https://github.com/Itseez/opencv/tree/master/data/haarcascades
沒有留言:
張貼留言