2024/04/17

OpenCV

簡介

OpenCV 的全稱是 Open Source Computer Vision Library, 是一個跨平台的電腦視覺庫,由英特爾公司發起並參與開發。

在 openSUSE Tumbleweed 安裝:

sudo zypper in opencv-devel

安裝完成以後,接下來進行是否安裝成功的測試。下面是一個顯示圖片的 display.cpp

#include <stdio.h>
#include <opencv2/opencv.hpp>

int main(int argc, char* argv[]) {

  if ( argc != 2 ) {
    printf("usage: display <File_Path>\n");
    return -1;
  }

  cv::Mat image = cv::imread( argv[1], 1 );

  if ( !image.data ) {
    printf("No image data\n");
    return -1;
  }

  cv::namedWindow("Display Image", cv::WINDOW_AUTOSIZE);
  cv::imshow("Display Image", image);
  cv::waitKey(0);
  cv::destroyWindow("Display Image");

  return 0;
}

如果直接編譯,使用:

g++ display.cpp -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_highgui -o display

或者是使用 pkg-config,假設是 OpenCV 4,那麼使用下列的指令:

g++ display.cpp `pkg-config opencv4 --libs` -o display

或者使用 CMake。這個例子所需要的 CMake 設定檔 CMakeLists.txt 內容如下:

cmake_minimum_required(VERSION 2.8)
project( DisplayImage )
find_package( OpenCV REQUIRED )
add_executable( display display.cpp )
target_link_libraries( display ${OpenCV_LIBS} )

接下來使用下列的指令編譯:

cmake .
make

要注意的是,OpenCL 預設使用的 color model 為 BGR,而一般流行使用的 color model 為 RGB。

還有的 color model 為 LAB:

  • L – Lightness ( Intensity ).
  • a – color component ranging from Green to Magenta.
  • b – color component ranging from Blue to Yellow.
cv::cvtColor(bright, brightLAB, cv::COLOR_BGR2LAB);

The YCrCb color space is derived from the RGB color space and has the following three compoenents.

  • Y – Luminance or Luma component obtained from RGB after gamma correction.
  • Cr = R – Y ( how far is the red component from Luma ).
  • Cb = B – Y ( how far is the blue component from Luma ).
cv::cvtColor(bright, brightYCB, cv::COLOR_BGR2YCrCb);

The HSV color space has the following three components

  • H – Hue ( Dominant Wavelength ).
  • S – Saturation ( Purity / shades of the color ).
  • V – Value ( Intensity ).
cv::cvtColor(bright, brightHSV, cv::COLOR_BGR2HSV);

要注意的是,要觀察圖片的軌跡或者是偵測線條(edge detection)時,很常用的手法是將圖轉為灰階,然後再使用各種演算法取得結果。


再來是建立一個空白的 image 並且顯示:

#include <opencv2/opencv.hpp>
#include <string>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
  Mat image(600, 800, CV_8UC3, Scalar(200, 150, 130));

  string windowName = "Window with Blank Image";

  namedWindow(windowName);
  imshow(windowName, image);
  waitKey(0);
  destroyWindow(windowName);

  return 0;
}

再來是讀取 Vedio 檔案並且播放的範例:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a vedio file." << endl;
        return 0;
    }

    VideoCapture vid_capture(argv[1]);

    if (!vid_capture.isOpened())
    {
        cout << "Error opening video stream or file" << endl;
    }

    else
    {
        int fps = vid_capture.get(CAP_PROP_FPS);
        cout << "Frames per second :" << fps;

        int frame_count = vid_capture.get(CAP_PROP_FRAME_COUNT);
        cout << "  Frame count :" << frame_count;
    }

    while (vid_capture.isOpened())
    {
        Mat frame;

        bool isSuccess = vid_capture.read(frame);

        if (isSuccess == true)
        {
            imshow("Frame", frame);
        }

        if (isSuccess == false)
        {
            cout << "Video camera is disconnected" << endl;
            break;
        }

        int key = waitKey(20);
        if (key == 'q')
        {
            cout << "q key is pressed by the user. Stopping the video" << endl;
            break;
        }
    }

    vid_capture.release();
    destroyAllWindows();
    return 0;
}

下面是 image resize 的例子:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    imshow("Original Image", image);

    int down_width = 300;
    int down_height = 200;
    Mat resized_down;
    resize(image, resized_down, Size(down_width, down_height), INTER_LINEAR);

    int up_width = 600;
    int up_height = 400;
    Mat resized_up;
    resize(image, resized_up, Size(up_width, up_height), INTER_LINEAR);

    imshow("Resized Down by defining height and width", resized_down);
    waitKey();
    imshow("Resized Up image by defining height and width", resized_up);
    waitKey();

    destroyAllWindows();
    return 0;
}

下面是 crop image 的例子:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat img = imread(argv[1]);
    cout << "Width : " << img.size().width << endl;
    cout << "Height: " << img.size().height << endl;
    cout << "Channels: :" << img.channels() << endl;

    int firstx = img.size().width / 4;
    int firsty = img.size().height / 4;
    int secondx = img.size().width / 4 * 3;
    int secondy = img.size().height / 4 * 3;

    Mat cropped_image = img(Range(firsty, secondy), Range(firstx, secondx));

    imshow(" Original Image", img);
    imshow("Cropped Image", cropped_image);

    //Save the cropped Image
    imwrite("CroppedImage.jpg", cropped_image);

    waitKey(0);
    destroyAllWindows();
    return 0;
}

下面是 image rotation 的例子:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    imshow("image", image);
    waitKey(0);
    double angle = 45;

    Point2f center((image.cols - 1) / 2.0, (image.rows - 1) / 2.0);
    Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0);

    Mat rotated_image;
    // rotate the image using warpAffine
    warpAffine(image, rotated_image, rotation_matix, image.size());
    imshow("Rotated image", rotated_image);
    waitKey(0);
    imwrite("rotated_im.jpg", rotated_image);

    return 0;
}

當我們對圖片加上某個常數,就是增加亮度或者是減少亮度。例如下面的式子是增加亮度:

new_image (i, j) = image(i, j) + c

所以我們可以這樣寫:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);

    if (image.empty())
    {
        cout << "Could not open or find the image" << endl;
        return 0;
    }

    Mat imageBrighnessHigh50;
    image.convertTo(imageBrighnessHigh50, -1, 1, 50); //increase the brightness by 50

    Mat imageBrighnessHigh100;
    image.convertTo(imageBrighnessHigh100, -1, 1, 100);

    Mat imageBrighnessLow50;
    image.convertTo(imageBrighnessLow50, -1, 1, -50); //decrease the brightness by 50

    Mat imageBrighnessLow100;
    image.convertTo(imageBrighnessLow100, -1, 1, -100);

    String windowNameOriginalImage = "Original Image";
    String windowNameBrightnessHigh50 = "Brightness Increased by 50";
    String windowNameWithBrightnessHigh100 = "Brightness Increased by 100";
    String windowNameBrightnessLow50 = "Brightness Decreased by 50";
    String windowNameBrightnessLow100 = "Brightness Decreased by 100";

    namedWindow(windowNameOriginalImage, WINDOW_NORMAL);
    namedWindow(windowNameBrightnessHigh50, WINDOW_NORMAL);
    namedWindow(windowNameWithBrightnessHigh100, WINDOW_NORMAL);
    namedWindow(windowNameBrightnessLow50, WINDOW_NORMAL);
    namedWindow(windowNameBrightnessLow100, WINDOW_NORMAL);

    imshow(windowNameOriginalImage, image);
    imshow(windowNameBrightnessHigh50, imageBrighnessHigh50);
    imshow(windowNameWithBrightnessHigh100, imageBrighnessHigh100);
    imshow(windowNameBrightnessLow50, imageBrighnessLow50);
    imshow(windowNameBrightnessLow100, imageBrighnessLow100);

    waitKey(0);
    destroyAllWindows();

    return 0;
}

對於 Contrast 來說,就是乘以某個數(> 1 就是增加對比,1 > c > 0 就是減少對比)。

new_image (i, j) = image(i, j) * c

所以我們可以這樣寫:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not open or find the image" << endl;
        cin.get();
        return 0;
    }

    Mat imageContrastHigh2;
    image.convertTo(imageContrastHigh2, -1, 2, 0); //increase the contrast by 2

    Mat imageContrastHigh4;
    image.convertTo(imageContrastHigh4, -1, 4, 0);

    Mat imageContrastLow0_5;
    image.convertTo(imageContrastLow0_5, -1, 0.5, 0);

    Mat imageContrastLow0_25;
    image.convertTo(imageContrastLow0_25, -1, 0.25, 0);

    String windowNameOriginalImage = "Original Image";
    String windowNameContrastHigh2 = "Contrast Increased by 2";
    String windowNameContrastHigh4 = "Contrast Increased by 4";
    String windowNameContrastLow0_5 = "Contrast Decreased by 0.5";
    String windowNameContrastLow0_25 = "Contrast Decreased by 0.25";

    namedWindow(windowNameOriginalImage, WINDOW_NORMAL);
    namedWindow(windowNameContrastHigh2, WINDOW_NORMAL);
    namedWindow(windowNameContrastHigh4, WINDOW_NORMAL);
    namedWindow(windowNameContrastLow0_5, WINDOW_NORMAL);
    namedWindow(windowNameContrastLow0_25, WINDOW_NORMAL);

    imshow(windowNameOriginalImage, image);
    imshow(windowNameContrastHigh2, imageContrastHigh2);
    imshow(windowNameContrastHigh4, imageContrastHigh4);
    imshow(windowNameContrastLow0_5, imageContrastLow0_5);
    imshow(windowNameContrastLow0_25, imageContrastLow0_25);

    waitKey(0);
    destroyAllWindows();

    return 0;
}

OpenCV 也具有繪圖(例如畫線、畫圓,以及加上文字等)的能力。下面是一個例子。

// Import dependencies
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat img = imread(argv[1]);
    imshow("Original Image", img);
    waitKey();
    if (img.empty())
    {
        cout << "Could not read image" << endl;
    }

    Mat imageChanged = img.clone();
    Point pointA(350, 370);
    Point pointB(500, 370);
    line(imageChanged, pointA, pointB, Scalar(255, 255, 0), 3, 8, 0);

    Point circle_center(420, 130);
    int radius = 150;
    circle(imageChanged, circle_center, radius, Scalar(0, 0, 255), 3, 8, 0);

    putText(imageChanged, "The best!", Point(50, 500), FONT_HERSHEY_COMPLEX,
            1.5, Scalar(250, 225, 100));

    imshow("Changed Image", imageChanged);
    waitKey();

    // save image
    imwrite("ChangedImage.jpg", imageChanged);
    destroyAllWindows();

    return 0;
}

下面是輸出的結果:


OpenCV 提供了函數 cv::threshold(),可以用來執行圖像二值化的工作。 圖像的二值化就是將圖像上的像素點的灰度值設置為 0 或 255,這樣將使整個圖像呈現出明顯的黑白效果。 在圖像處理中,二值圖像佔有非常重要的地位,圖像的二值化使圖像的數據大為減少,從而凸顯出目標的輪廓。

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat src = imread(argv[1], IMREAD_GRAYSCALE);
    Mat dst;


    // Basic threhold example
    threshold(src,dst,0, 255, THRESH_BINARY);
    imwrite("opencv-threshold-example.jpg", dst);

    // Thresholding with maxval set to 128
    threshold(src, dst, 0, 128, THRESH_BINARY);
    imwrite("opencv-thresh-binary-maxval.jpg", dst);

    // Thresholding with threshold value set 127
    threshold(src,dst,127,255, THRESH_BINARY);
    imwrite("opencv-thresh-binary.jpg", dst);

    // Thresholding using THRESH_BINARY_INV
    threshold(src,dst,127,255, THRESH_BINARY_INV);
    imwrite("opencv-thresh-binary-inv.jpg", dst);

    // Thresholding using THRESH_TRUNC
    threshold(src,dst,127,255, THRESH_TRUNC);
    imwrite("opencv-thresh-trunc.jpg", dst);

    // Thresholding using THRESH_TOZERO
    threshold(src,dst,127,255, THRESH_TOZERO);
    imwrite("opencv-thresh-tozero.jpg", dst);

    // Thresholding using THRESH_TOZERO_INV
    threshold(src,dst,127,255, THRESH_TOZERO_INV);
    imwrite("opencv-thresh-to-zero-inv.jpg", dst);
}

Histogram of an image is the graphical representation of the distribution of intensities of pixels. It provides an estimate of where pixel values are concentrated and whether there are unusual deviations.

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);

    if (image.empty())
    {
        cout << "Could not open or find the image" << endl;
        return 0;
    }

    cvtColor(image, image, COLOR_BGR2GRAY);

    Mat hist_equalized_image;
    equalizeHist(image, hist_equalized_image);

    String windowNameOfOriginalImage = "Original Image";
    String windowNameOfHistogramEqualized = "Histogram Equalized Image";

    namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL);
    namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL);

    imshow(windowNameOfOriginalImage, image);
    imshow(windowNameOfHistogramEqualized, hist_equalized_image);

    waitKey(0);
    destroyAllWindows();
}

下面是針對彩色的範例:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not read image" << endl;
    }

    Mat hist_equalized_image;
    cvtColor(image, hist_equalized_image, COLOR_BGR2YCrCb);

    vector<Mat> vec_channels;
    split(hist_equalized_image, vec_channels);

    equalizeHist(vec_channels[0], vec_channels[0]);

    merge(vec_channels, hist_equalized_image);

    cvtColor(hist_equalized_image, hist_equalized_image, COLOR_YCrCb2BGR);

    String windowNameOfOriginalImage = "Original Image";
    String windowNameOfHistogramEqualized = "Histogram Equalized Color Image";

    namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL);
    namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL);

    imshow(windowNameOfOriginalImage, image);
    imshow(windowNameOfHistogramEqualized, hist_equalized_image);

    waitKey(0); // Wait for any keystroke in any one of the windows

    destroyAllWindows(); //Destroy all opened windows

    return 0;
}

equalizeHist 在一些情況下會製造雜訊,也可以使用 CLAHE 來作為改進的演算法:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not read image" << endl;
    }

    Mat hist_equalized_image;
    cvtColor(image, hist_equalized_image, COLOR_BGR2YCrCb);

    vector<Mat> vec_channels;
    Ptr<CLAHE> clahe = createCLAHE();
    split(hist_equalized_image, vec_channels);

    clahe->apply(vec_channels[0], vec_channels[0]);

    merge(vec_channels, hist_equalized_image);

    cvtColor(hist_equalized_image, hist_equalized_image, COLOR_YCrCb2BGR);

    String windowNameOfOriginalImage = "Original Image";
    String windowNameOfHistogramEqualized = "Histogram Equalized Color Image";

    namedWindow(windowNameOfOriginalImage, WINDOW_NORMAL);
    namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL);

    imshow(windowNameOfOriginalImage, image);
    imshow(windowNameOfHistogramEqualized, hist_equalized_image);

    waitKey(0); // Wait for any keystroke in any one of the windows

    destroyAllWindows(); //Destroy all opened windows

    return 0;
}

Edge detection is an image-processing technique, which is used to identify the boundaries (edges) of objects, or regions within an image.

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat img = imread(argv[1]);

    if (img.empty())
    {
        cout << "Could not open or find the image" << endl;
        return 0;
    }
    imshow("original Image", img);
    waitKey(0);

    Mat img_gray;
    cvtColor(img, img_gray, COLOR_BGR2GRAY);
    Mat img_blur;
    GaussianBlur(img_gray, img_blur, Size(3,3), 0);

    Mat sobelx, sobely, sobelxy;
    Sobel(img_blur, sobelx, CV_64F, 1, 0, 5);
    Sobel(img_blur, sobely, CV_64F, 0, 1, 5);
    Sobel(img_blur, sobelxy, CV_64F, 1, 1, 5);
    imshow("Sobel X", sobelx);
    waitKey(0);
    imshow("Sobel Y", sobely);
    waitKey(0);
    imshow("Sobel XY using Sobel() function", sobelxy);
    waitKey(0);

    Mat edges;
    Canny(img_blur, edges, 100, 200, 3, false);
    imshow("Canny edge detection", edges);
    waitKey(0);

    destroyAllWindows();
    return 0;
}

The image filtering is a neighborhood operation in which the value of any given pixel in the output image is determined by applying a certain algorithm to the pixel values ​​in the vicinity of the corresponding input pixel.

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not read image" << endl;
    }

    Mat image_blurred_with_3x3_kernel;
    blur(image, image_blurred_with_3x3_kernel, Size(3, 3));

    Mat image_blurred_with_5x5_kernel;
    blur(image, image_blurred_with_5x5_kernel, Size(5, 5));

    String window_name = "Display";
    String window_name_blurred_with_3x3_kernel = "Display Blurred with 3 x 3 Kernel";
    String window_name_blurred_with_5x5_kernel = "Display Blurred with 5 x 5 Kernel";

    namedWindow(window_name);
    namedWindow(window_name_blurred_with_3x3_kernel);
    namedWindow(window_name_blurred_with_5x5_kernel);

    imshow(window_name, image);
    imshow(window_name_blurred_with_3x3_kernel, image_blurred_with_3x3_kernel);
    imshow(window_name_blurred_with_5x5_kernel, image_blurred_with_5x5_kernel);

    waitKey(0);
    destroyAllWindows();

    return 0;
}

下面是另外的例子:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not read image" << endl;
    }

    Mat kernel1 = (Mat_<double>(3, 3) << 0, 0, 0, 0, 1, 0, 0, 0, 0);
    Mat identity;
    filter2D(image, identity, -1, kernel1, Point(-1, -1), 0, 4);
    imshow("Original", image);
    imshow("Identity", identity);
    waitKey();
    imwrite("identity.jpg", identity);
    destroyAllWindows();

    Mat kernel2 = Mat::ones(5, 5, CV_64F);
    kernel2 = kernel2 / 25;
    Mat img;
    filter2D(image, img, -1, kernel2, Point(-1, -1), 0, 4);
    imshow("Original", image);
    imshow("Kernel blur", img);
    imwrite("blur_kernel.jpg", img);
    waitKey();
    destroyAllWindows();
}

下面是 mouse callback function 的例子:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void CallBackFunc(int event, int x, int y, int flags, void *userdata)
{
    if (event == EVENT_LBUTTONDOWN)
    {
        cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    }
    else if (event == EVENT_RBUTTONDOWN)
    {
        cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    }
    else if (event == EVENT_MBUTTONDOWN)
    {
        cout << "Middle button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;
    }
    else if (event == EVENT_MOUSEMOVE)
    {
        cout << "Mouse move over the window - position (" << x << ", " << y << ")" << endl;
    }
}

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        cout << "Please give a file." << endl;
        return 0;
    }

    Mat image = imread(argv[1]);
    if (image.empty())
    {
        cout << "Could not read image" << endl;
    }

    namedWindow("My Window", 1);
    setMouseCallback("My Window", CallBackFunc, NULL);
    imshow("My Window", image);
    waitKey(0);
    destroyAllWindows();
    return 0;
}

使用 SimpleBlobDetector 執行 Blob detection:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char *argv[])
{
    Mat im = imread("blob.jpg", IMREAD_GRAYSCALE);

    // Setup SimpleBlobDetector parameters.
    SimpleBlobDetector::Params params;

    // Change thresholds
    params.minThreshold = 10;
    params.maxThreshold = 200;

    // Filter by Area.
    //params.filterByArea = true;
    //params.minArea = 1500;

    // Filter by Circularity
    //params.filterByCircularity = true;
    //params.minCircularity = 0.1;

    // Filter by Convexity
    params.filterByConvexity = true;
    params.minConvexity = 0.5;

    // Filter by Inertia
    //params.filterByInertia = true;
    //params.minInertiaRatio = 0.01;

    Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);

    std::vector<KeyPoint> keypoints;
    detector->detect(im, keypoints);

    Mat im_with_keypoints;
    drawKeypoints(im, keypoints, im_with_keypoints, Scalar(0, 0, 255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    namedWindow("keypoints", 1);
    imshow("keypoints", im_with_keypoints);
    waitKey(0);
}

下面是針對單一圖片的 Face Detection 例子。如果要改寫成使用 camera,那就是你拿到 frame 以後,使用同樣的方式去偵測。

#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace std;
using namespace cv;

CascadeClassifier face_cascade;

int main( int argc, const char** argv )
{
    if ( argc != 2 ) {
        printf("usage: display <File_Path>\n");
        return -1;
    }

    /*
     * From https://github.com/opencv/opencv/tree/master/data/haarcascades
     */
    string face_cascade_name("haarcascade_frontalface_default.xml");

    if( !face_cascade.load( face_cascade_name ) )
    {
        cout << "--(!)Error loading face cascade\n";
        return -1;
    };

    cv::Mat frame = cv::imread( argv[1], 1 );
    if ( !frame.data ) {
        printf("No image data\n");
        return -1;
    }
    cv::namedWindow("Display", cv::WINDOW_AUTOSIZE);

    Mat frame_gray;
    cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    std::vector<Rect> faces;
    face_cascade.detectMultiScale( frame_gray, faces );
    cout << "Find: " << faces.size() << endl;
    for (auto&& feature : faces) {
        cv::rectangle(frame, feature, cv::Scalar(0, 0, 255), 2);
    }

    imshow( "Display", frame );
    waitKey(0);
    return 0;
}

參考連結

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。