Opencv C++ 学习视频整理源代码(1)

发布时间:2022-08-19 13:08


0.代码基本框架
#include
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char ** agrv)
{
    waitKey(0);
    return -1;
}


1.调试代码:

#include
#include

using namespace cv;
int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (src.empty())
    {
        printf("could not load image....\n");
        return - 1;
    }

    namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
    imshow("test opencv setup", src);

    waitKey(0);
    return 0;
}

2.加载、修改、保存图像
#include
#include
#include

using namespace cv;
int main(int argc, char** argv)
{
    Mat src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }

    namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
    imshow("opencv setup demo", src);//显示图像(原始图像)

    namedWindow("output windows", CV_WINDOW_AUTOSIZE);//设置图像显示窗口大小
    Mat output_image;
    cvtColor(src, output_image, CV_BGR2HLS);//将彩色图像改变成HLS图像
    imshow("output windows", output_image);

    imwrite("C:/Users/25503/Desktop/张教授项目/1.png",output_image);//保存图像,包括保存类型和路径

    waitKey(0);
    return 0;
}

3.对比度提高(1)
#include
#include
#include

using namespace cv;
int main(int argc, char** argv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }

    namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
    imshow("opencv setup demo", src);//显示图像(原始图像)

    int cols = (src.cols - 1)*src.channels();
    int offsetx = src.channels();
    int rows = src.rows;
    dst = Mat::zeros(src.size(), src.type());
    for (int row = 1; row < (rows - 1); row++)
    {
        const uchar* previous = src.ptr(row - 1);
        const uchar* current = src.ptr(row);
        const uchar* next = src.ptr(row + 1);
        uchar* output = dst.ptr(row);
        for (int col = offsetx; col < cols; col++)
        {
            output[col] = saturate_cast(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
        }


    }
    namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
    imshow("test opencv setup", dst);

    waitKey(0);
    return 0;

}

3.对比度提高(2)
#include
#include
#include

using namespace cv;
int main(int argc, char** argv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }

    namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
    imshow("opencv setup demo", src);//显示图像(原始图像)

    /*int cols = (src.cols - 1)*src.channels();
    int offsetx = src.channels();
    int rows = src.rows;
    dst = Mat::zeros(src.size(), src.type());
    for (int row = 1; row < (rows - 1); row++)
    {
        const uchar* previous = src.ptr(row - 1);
        const uchar* current = src.ptr(row);
        const uchar* next = src.ptr(row + 1);
        uchar* output = dst.ptr(row);
        for (int col = offsetx; col < cols; col++)
        {
            output[col] = saturate_cast(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
        }


    }
    */

    Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    filter2D(src, dst, src.depth(), kernel);
    namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
    imshow("test opencv setup", dst);

    waitKey(0);
    return 0;

}

4.调节图像的对比度和亮度
5.图像模糊
6.视频读写(1)--读取已保存的.mp4文件
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    VideoCapture capture;
    capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
    if (!capture.isOpened())
    {
        printf("could not load video data....\n");
        return -1;
    }

    Mat frame;
    namedWindow("video-demo", CV_WINDOW_AUTOSIZE);
    while (capture.read(frame))
    {
        imshow("video-demo", frame);
        char c = waitKey(100);
        if (c == 27)
        {
            break;
        }
    }

    waitKey(0);
    return 0;
}
6.视频读写(2)--打开摄像头读取文件.mp4文件
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    VideoCapture capture(0);//打开摄像头
    //capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");//从已保存的文件中读取视频
    if (!capture.isOpened())
    {
        printf("could not load video data....\n");
        return -1;
    }

    Mat frame;
    namedWindow("video-demo", CV_WINDOW_AUTOSIZE);
    while (capture.read(frame))
    {
        imshow("video-demo", frame);
        char c = waitKey(100);
        if (c == 27)
        {
            break;
        }
    }

    waitKey(0);
    return 0;
}

7.基于颜色轨迹跟踪
#include
#include

using namespace std;
using namespace cv;

Rect roi;
void processFrame(Mat &binary, Rect &rect);

int main()
{
    // load video
    VideoCapture capture;
    capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
    if (!capture.isOpened())
    {
        printf("could not find video file....\n");
        return -1;
    }

    Mat frame,mask;
    Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
    namedWindow("input video", CV_WINDOW_AUTOSIZE);
    namedWindow("track mask", CV_WINDOW_AUTOSIZE);
    while (capture.read(frame))
    {
        
        inRange(frame, Scalar(0, 127, 0), Scalar(120, 255, 120), mask);//过滤
        morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1), 1);//开运算
        dilate(mask, mask, kernel2, Point(-1, -1), 4);//膨胀
        imshow("track mask", mask);
        processFrame(mask, roi);//轮廓发现与位置标定
        rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);

        imshow("input video", frame);
        
        
        //trigger exit
        char c = waitKey(1);
        if (c == 27)
        {
            break;
        }
    }

    capture.release();
    waitKey(0);
    return 0;
}
void processFrame(Mat &binary, Rect &rect)
{
    vector > contours;
    vector hireachy;
    findContours(binary, contours, hireachy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0,0));
    if (contours.size() > 0)
    {
        double maxArea = 0.0;
        for (size_t t = 0; t < contours.size(); t++)
        {
            double area = contourArea(contours[static_cast(t)]);
            if (area > maxArea)
            {
                maxArea = area;
                rect = boundingRect(contours[static_cast(t)]);
            }
        }
    }
    else
    {
        rect.x = rect.y = rect.width = rect.height = 0;
    }
}


8.单目标开摄像头跟踪
#include
#include

using namespace std;
using namespace cv;

Rect roi;
void processFrame(Mat &binary, Rect &rect);

int main()
{
    // load video
    VideoCapture capture(0);//打开摄像头
    //VideoCapture capture;
    //capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
    if (!capture.isOpened())
    {
        printf("could not find video file....\n");
        return -1;
    }

    Mat frame, mask;
    Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
    namedWindow("input video", CV_WINDOW_AUTOSIZE);
    namedWindow("track mask", CV_WINDOW_AUTOSIZE);
    while (capture.read(frame))
    {

        inRange(frame, Scalar(220, 220, 220), Scalar(255, 255, 255), mask);//过滤
        imshow("track mask1", mask);
        morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1), 1);//开运算
        dilate(mask, mask, kernel2, Point(-1, -1), 4);//膨胀
        imshow("track mask2", mask);
        processFrame(mask, roi);//轮廓发现与位置标定
        rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);//BGR

        imshow("input video", frame);


        //trigger exit
        char c = waitKey(1);
        if (c == 27)
        {
            break;
        }
    }

    capture.release();
    waitKey(0);
    return 0;
}
void processFrame(Mat &binary, Rect &rect)
{
    vector > contours;
    vector hireachy;
    findContours(binary, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
    if (contours.size() > 0)
    {
        double maxArea = 0.0;
        for (size_t t = 0; t < contours.size(); t++)
        {
            double area = contourArea(contours[static_cast(t)]);
            if (area > maxArea)
            {
                maxArea = area;
                rect = boundingRect(contours[static_cast(t)]);
            }
        }
    }
    else
    {
        rect.x = rect.y = rect.width = rect.height = 0;
    }
}

9.单目标跟踪方法:TrackerKCF速度快、基本好用;TrackerBoosting;TrackerMIL;TrackerMedianFlow;TrackerTLD
#include
#include
#include

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    VideoCapture capture;
    capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");//读取视频
    if (!capture.isOpened())
    {
        printf("could not load video data....\n");
        return -1;
    }
    Mat frame;
    namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
    Ptr tracker = TrackerMIL::create();//MIL跟踪算法,也可以改成另外其它算法
    capture.read(frame);
    Rect2d roi = selectROI("tracker demo", frame);
    if (roi.width == 0 || roi.height == 0)
    {
        return -1;
    }
    tracker->init(frame, roi);
    while (capture.read(frame))
    {
        tracker->update(frame, roi);
        rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
        imshow("track demo", frame);

        char c = waitKey(20);
        if (c == 27)
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}


(2)单目标图像跟踪程序
#include
#include
#include

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    VideoCapture capture(0);//打开摄像头
    if (!capture.isOpened())
    {
        printf("could not load video data....\n");
        return -1;
    }
    Mat frame;
    namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
    Ptr tracker = TrackerBoosting::create();//MIL跟踪算法,也可以改成另外其它算法
    capture.read(frame);
    Rect2d roi = selectROI("tracker demo", frame);
    if (roi.width == 0 || roi.height == 0)
    {
        return -1;
    }
    tracker->init(frame, roi);
    while (capture.read(frame))
    {
        tracker->update(frame, roi);
        rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
        imshow("track demo", frame);

        char c = waitKey(20);
        if (c == 27)
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}

多目标跟踪1*****失败,因为OpenCV 教学视频与自己的版本不同,最终调试好的可参考P123中的(2)
#include
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char ** agrv)
{
    VideoCapture capture;
    capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
    if (!capture.isOpened())
    {
        printf("could not load data....\n");
        return -1;
    }
    namedWindow("Multiple Objects Tracking", CV_WINDOW_AUTOSIZE);
    Ptr trackers = MultiTracker::create();//MIL跟踪算法,也可以改成另外其它算法
    vector objects;
    
    Mat frame, gray;
    capture.read(frame);
    selectROIs("Multiple Object Tracking", frame, objects);
    if (objects.size() < 1)
    {
        return -1;
    }
    trackers.add(frame, objects);
    while (capture.read(frame))
    {
        trackers.update(frame);
        for (size_t t = 0; t < trackers.getObjects.size(); t++)
        {
            rectangle(frame, trackers.objects[t], Scalar(0, 0, 255), 2, 8, 0);

        }
        imshow("Multiple Objects Tracking", frame);
        char c = waitKey(50);
        if (c == 27)
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return -1;
}

单目标跟踪
#include //opencv头文件

bool selectObject = false; //用于是否有选取目标
int trackObject = 0; // 1表示有追踪对象 0 表示无追踪对象 
                     //-1表示追踪对象尚未计算camshift所需的属性                  
cv::Rect selection;//保存鼠标选择的区域
cv::Mat image;//用于缓存读取到的视频帧
/*
opencv 对所注册的鼠标回调函数定义为:
void onMouse(int event,int x,int y,int flag,void * param)
其中第四个flag为event下的附加状态,param是用户传入的参数
*/
void onMouse( int event, int x, int y, int, void* ) {
    static cv::Point origin;
    /*static关键字的作用:
      1、隐藏功能 利用这一特性可以在不同的文件中定义同名函数和同名变量
      2、保持变量内容的持久
    */
    if(selectObject) {//如果检测到选取目标进行下面的操作
        //确定鼠标选定区域的左上角坐标以及区域的长和宽
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        //&运算符被cv::Rect进行重载
        //表示两个区域的交集,主要目的是为了处理当鼠标在选择区域时移除画面外
        selection &= cv::Rect(0, 0, image.cols, image.rows);
    }
    switch(event) {
        //处理鼠标左键被按下
        case CV_EVENT_LBUTTONDOWN:
            origin = cv::Point(x, y);
            selection = cv::Rect(x, y, 0, 0);
            selectObject = true;
            break;
            //处理鼠标左键被抬起
        case CV_EVENT_LBUTTONUP:
            selectObject = false;
            if( selection.width > 0 && selection.height > 0 )
                trackObject = -1;//追踪的目标还未计算camshift所需要的属性
            break;
    }
}

int main( int argc, const char** argv )
{
    cv::VideoCapture video("video.ogv");//读取文件
    //如果需要使用摄像头则代码为
    //cv::VideoCapture video(0);

    cv::namedWindow( "test" );
    //注册鼠标事件的回调函数,第三个参数是用户提供给回掉函数的
    //也就是回调函数中最后的param参数
    cv::setMouseCallback( "test", onMouse, 0 );

/*
捕获画面的容器,opencv中的mat对象
opencv中最关键的mat类,mat是matrix的缩写
opencv中延续了像素图的概念,用矩阵来描述由像素构成的图像
*/
    cv::Mat frame, hsv, hue, mask, hist, backproj;
    cv::Rect trackWindow; //追踪到的窗口
    int hsize = 16;//计算直方图所必备的内容
    float hranges[] = {0,180};//计算直方图所必备的内容
    const float* phranges = hranges;//计算直方图所必备的内容

    while(true) {
        //将video中的内容写入到frame中,
        //这里的>>运算符是经过opencv重载的
        video >> frame;
        if( frame.empty() )//没有帧可以读取的时候,退出循环
            break;
        //将frame中的图像写入全局变量image作为进行camshift的缓存
        frame.copyTo(image);
        //转换到的HSV空间
        cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
        //当有目标时候进行处理
        if( trackObject ) {
            // 只处理像素值为H:0~180,S:30~256,V:10~256之间的部分,过滤掉其他的部分并复制给 mask
            cv::inRange(hsv, cv::Scalar(0, 30, 10), cv::Scalar(180, 256, 256), mask);
            //下面三句将hsv图像中的H通道分离出来
            int ch[] = {0, 0};
            hue.create(hsv.size(), hsv.depth());
            cv::mixChannels(&hsv, 1, &hue, 1, ch, 1);
            //如果需要追踪的物体还没有进行属性提取,则对选择的目标中的图像属性提取
            if( trackObject < 0 ) {
                //设置H通道和mask图像的ROI
                cv::Mat roi(hue, selection), maskroi(mask, selection);
                //计算ROI所在区域的直方图
                calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                //将直方图归一
                normalize(hist, hist, 0, 255, CV_MINMAX);
                //设置追踪的窗口
                trackWindow = selection;
                //标记追踪的目标已经计算过直方图属性
                trackObject = 1;
            }
            //将直方图进行反向投影
            calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
            //取公共部分
            backproj &= mask;
            //调用camshift算法的接口
            cv::RotatedRect trackBox = CamShift(backproj, trackWindow, cv::TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
            //处理追踪面积过小的情况
            if( trackWindow.area() <= 1 ) {
                int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
                trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
                                   trackWindow.x + r, trackWindow.y + r) &
                cv::Rect(0, 0, cols, rows);
            }
            //绘制追踪区域
            ellipse( image, trackBox, cv::Scalar(0,0,255), 3, CV_AA );

        }
        //如果正在选择追踪目标,则画出选择框
        if( selectObject && selection.width > 0 && selection.height > 0 ) {
            cv::Mat roi(image, selection);
            bitwise_not(roi, roi);//对选择的区域图像反色
        }

        imshow( "test", image );//显示当前帧
         // 录制视频帧率为 15, 等待 1000/15 保证视频播放流畅。
        // waitKey(int delay) 是 OpenCV 提供的一个等待函数,
        // 当运行到这个函数时会阻塞 delay 毫秒的时间来等待键盘输入
        char c = (char)cv::waitKey(1000/15.0);
        if( c == 27 )//当按键为esc时,退出循环
            break;
    }
    //释放申请的相关内存
    cv::destroyAllWindows();
    video.release();
    return 0;
}


/*以下为本程序仿真步骤
需要安装opencv、opengl
提供linux环境下安装opencv的方法
sudo apt-get install libopencv-dev
linux环境安装opengl的命令
//sudo apt-get update && sudo apt-get install freeglut3 freeglut3-dev

另外提供安装linux环境下的屏幕录制工具
sudo apt-get update && sudo apt-get install gtk-recordmydesktop
linux环境下编译命令
g++ main.cpp `pkg-config opencv --libs --cflags opencv` -o  main
*/

2多目标跟踪
// Opencv_MultiTracker.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//


#include
#include
#include

using namespace cv;
using namespace std;

vector trackerTypes = { "BOOSTING", "MIL", "KCF", "TLD", "MEDIANFLOW", "GOTURN", "MOSSE", "CSRT" };

/**
 * @brief Create a Tracker By Name object 根据设定的类型初始化跟踪器
 *
 * @param trackerType
 * @return Ptr
 */
Ptr createTrackerByName(string trackerType)
{
    Ptr tracker;
    if (trackerType == trackerTypes[0])
        tracker = TrackerBoosting::create();
    else if (trackerType == trackerTypes[1])
        tracker = TrackerMIL::create();
    else if (trackerType == trackerTypes[2])
        tracker = TrackerKCF::create();
    else if (trackerType == trackerTypes[3])
        tracker = TrackerTLD::create();
    else if (trackerType == trackerTypes[4])
        tracker = TrackerMedianFlow::create();
    else if (trackerType == trackerTypes[5])
        tracker = TrackerGOTURN::create();
    else if (trackerType == trackerTypes[6])
        tracker = TrackerMOSSE::create();
    else if (trackerType == trackerTypes[7])
        tracker = TrackerCSRT::create();
    else
    {
        cout << "Incorrect tracker name" << endl;
        cout << "Available trackers are: " << endl;
        for (vector::iterator it = trackerTypes.begin(); it != trackerTypes.end(); ++it)
        {
            std::cout << " " << *it << endl;
        }
    }
    return tracker;
}

/**
 * @brief Get the Random Colors object 随机涂色
 *
 * @param colors
 * @param numColors
 */
void getRandomColors(vector &colors, int numColors)
{
    RNG rng(0);
    for (int i = 0; i < numColors; i++)
    {
        colors.push_back(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
    }
}

int main(int argc, char *argv[])
{
    // Set tracker type. Change this to try different trackers. 选择追踪器类型
    string trackerType = trackerTypes[7];

    // set default values for tracking algorithm and video 视频读取
    //string videoPath = "video/run.mp4";
    VideoCapture cap(0);//打开摄像头

    // Initialize MultiTracker with tracking algo 边界框
    vector bboxes;

    // create a video capture object to read videos 读视频
    //cv::VideoCapture cap(videoPath);
    Mat frame;

    // quit if unable to read video file
    if (!cap.isOpened())
    {
        printf("could not load video data....\n");
        return -1;
    }

    // read first frame 读第一帧
    cap >> frame;

    // draw bounding boxes over objects 在第一帧内确定对象框
    /*
        先在图像上画框,然后按ENTER确定画下一个框。按ESC退出画框开始执行程序
    */
    cout << "\n==========================================================\n";
    cout << "OpenCV says press c to cancel objects selection process" << endl;
    cout << "It doesn't work. Press Esc to exit selection process" << endl;
    cout << "\n==========================================================\n";
    cv::selectROIs("MultiTracker", frame, bboxes, false);

    //自己设定对象的检测框
    //x,y,width,height
    //bboxes.push_back(Rect(388, 155, 30, 40));
    //bboxes.push_back(Rect(492, 205, 50, 80));
    // quit if there are no objects to track 如果没有选择对象
    if (bboxes.size() < 1)
    {
        return 0;
    }

    vector colors;
    //给各个框涂色
    getRandomColors(colors, bboxes.size());

    // Create multitracker 创建多目标跟踪类
    Ptr multiTracker = cv::MultiTracker::create();

    // initialize multitracker 初始化
    for (int i = 0; i < bboxes.size(); i++)
    {
        multiTracker->add(createTrackerByName(trackerType), frame, Rect2d(bboxes[i]));
    }

    // process video and track objects 开始处理图像
    cout << "\n==========================================================\n";
    cout << "Started tracking, press ESC to quit." << endl;
    while (cap.isOpened())
    {
        // get frame from the video 逐帧处理
        cap >> frame;

        // stop the program if reached end of video
        if (frame.empty())
        {
            break;
        }

        //update the tracking result with new frame 更新每一帧
        bool ok = multiTracker->update(frame);
        if (ok == true)
        {
            cout << "Tracking success" << endl;
        }
        else
        {
            cout << "Tracking failure" << endl;
        }
        // draw tracked objects 画框
        for (unsigned i = 0; i < multiTracker->getObjects().size(); i++)
        {
            rectangle(frame, multiTracker->getObjects()[i], colors[i], 2, 1);
        }

        // show frame
        imshow("MultiTracker", frame);

        // quit on x button
        if (waitKey(1) == 27)
        {
            break;
        }
    }
    waitKey(0);
    return 0;
}


P09模糊图像//2021/1/5 均值模糊和高斯模糊
# include
# include

using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    char input_title[] = "input image";
    char output_title[] = "blur image";
    namedWindow(input_title, CV_WINDOW_AUTOSIZE);
    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    imshow(input_title, src);

    blur(src, dst, Size(9, 3), Point(-1, -1));//均值模糊
    imshow(output_title, dst);

    Mat gblur;
    GaussianBlur(src, gblur, Size(9, 3), 11, 11);//高斯模糊
    imshow("gaussian blur", gblur);

    waitKey(0);
    return 0;

}

P10中值滤波(对椒盐噪声抑制很好)、高斯双边滤波(能够很好的保留图像边缘信息)***
# include
# include

using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    

    namedWindow("input_title", CV_WINDOW_AUTOSIZE);
    imshow("input_title", src);

    //medianBlur(src, dst, 3)
    bilateralFilter(src, dst, 15, 100, 5);
    namedWindow("BiBlur Filter result", CV_WINDOW_AUTOSIZE);
    imshow("BiBlur Filter result", dst);

    Mat resultImg;
    Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    filter2D(dst, resultImg, -1, kernel, Point(-1, -1), 0);
    imshow("Final result", resultImg);
    

    waitKey(0);
    return 0;

}

P11膨胀与腐蚀
# include
# include

using namespace cv;

Mat src, dst;
char OUTPUT_WIN[] = "output image";
int element_size = 3;
int max_size = 21;
void CallBack_Demo(int, void*);
int main(int argc, char** agrv)
{
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    

    namedWindow("input_title", CV_WINDOW_AUTOSIZE);
    imshow("input_title", src);

    namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    createTrackbar("Element Size:", OUTPUT_WIN, &element_size, max_size, CallBack_Demo);
    CallBack_Demo(0, 0);
    
    waitKey(0);
    return 0;
}
void CallBack_Demo(int, void*)
{
    int s = element_size * 2 + 1;
    Mat structureElement = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));//Size(x,y)中的x,y可以调节
    dilate(src, dst, structureElement, Point(-1, -1), 1);//膨胀
    //erode(src, dst, structureElement);//腐蚀
    imshow(OUTPUT_WIN, dst);
    return;
}

P12形态学操作2021/1/6
开操作open、闭操作close、形态学梯度、顶帽top_hat、黑帽
# include
# include

using namespace cv;

int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    

    namedWindow("input_title", CV_WINDOW_AUTOSIZE);
    imshow("input_title", src);
               char out_title[] = "morphology demo";
    namedWindow(out_title, CV_WINDOW_AUTOSIZE);

    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    //morphologyEx(src, dst, CV_MOP_OPEN, kernel);//先腐蚀后膨胀,可以去掉小的对象,假设对象是前景色,背景是黑色
    //morphologyEx(src, dst, CV_MOP_CLOSE, kernel);//先膨胀后腐蚀,可以填充小的洞,假设对象是前景色,背景是黑色
    //morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);//膨胀减去腐蚀
    //morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);//顶帽是原图像与开操作之间的差值图像
    morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);//黑帽是闭操作图像与源图像的差值图像
    imshow(out_title, dst);
    waitKey(0);
    return 0;
}

P13形态学操作-提取水平线、竖直线、字母*******
# include
# include

using namespace cv;

int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/124.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "result image";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_WIN, src);

    Mat gray_src;
    cvtColor(src, gray_src, CV_BGR2GRAY);//彩色图转换为灰度图
    imshow("gray image", gray_src);

    Mat binImg;
    adaptiveThreshold(gray_src, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//灰度图转换为二值图
    imshow("binary image", binImg);

    Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));//定义水平线提取元素
    Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.cols / 16), Point(-1, -1));//定义数值线提取元素
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//矩形元素提取
    /*读取直线或者竖直线操作*/
    Mat temp_h;
    //erode(binImg, temp_h, hline);//腐蚀
    //dilate(temp_h, dst, hline);//膨胀
    morphologyEx(binImg, dst, CV_MOP_OPEN, hline);//开操作相当于先腐蚀后膨胀
    bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
    blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
    imshow("Final Result hline", dst);//得到水平线

    /*读取直线或者竖直线操作*/
    Mat temp_v;
    erode(binImg, temp_v, vline);//腐蚀
    dilate(temp_v, dst, vline);//膨胀
    bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
    blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
    imshow("Final Result vline", dst);//得到水平线


    /*矩形元素提取*/
    Mat temp_JuXing;
    erode(binImg, temp_JuXing, kernel);//腐蚀
    dilate(temp_JuXing, dst, kernel);//膨胀
    bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
    //blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
    imshow("Final Result Juxing", dst);//得到矩形

    waitKey(0);
    return 0;
}

P14图像金字塔-上采样与下采样
# include
# include
# include


using namespace cv;

int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/124.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }


    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "result image";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_WIN, src);

    //上采样表示图像比原来图像宽高增大2倍或者几倍
    pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
    imshow(OUTPUT_WIN, dst);

    //下采样表示图像比原来图像宽高缩小2倍或者几倍
    Mat s_down;
    pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));
    imshow("sample down", s_down);


    //高斯不同DOG******
    Mat gray_src, g1, g2, dogImg;
    cvtColor(src, gray_src, CV_BGR2GRAY);//RGB彩色图像转换为灰度图像
    GaussianBlur(gray_src, g1, Size(3, 3), 0, 0);//高斯模糊得到g1
    GaussianBlur(g1, g2, Size(3, 3), 0, 0);//再次高斯模糊得到g2
    subtract(g1, g2, dogImg, Mat());//从g1中减去g2,得到dogImg
    normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);
    imshow("DOG Image", dogImg);

    waitKey(0);
    return 0;
}

P15基本阈值操作
# include
# include
# include


using namespace cv;
Mat src, gray_src, dst;
int threshold_value = 127;
int threshold_max = 255;
const char* output_title = "binary image";
void Threshold_Demo(int, void*);

int main(int argc, char** agrv)
{
    src = imread("C:/Users/25503/Desktop/124.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    imshow("input image", src);
    cvtColor(src, gray_src, CV_BGR2GRAY);
    createTrackbar("Threshold Value:", output_title, &threshold_value, threshold_max, Threshold_Demo);
    Threshold_Demo(0, 0);

    waitKey(0);
    return 0;
}
void Threshold_Demo(int, void*)
{
    cvtColor(src, gray_src, CV_BGR2GRAY);//彩色图像转换为灰度图像
    threshold(gray_src, dst, threshold_value, threshold_max, THRESH_BINARY);//正常阈值分割,背景为白色,还有其他阈值方法
    threshold(gray_src, dst, threshold_value, threshold_max, THRESH_BINARY_INV);//反阈值分割,背景为黑色
    imshow(output_title, dst);
}

P16自定义滤波(Robat算子、索贝尔算子、拉布拉斯算子、自定义卷积模糊)
# include
# include
# include


using namespace cv;

int main(int argc, char** agrv)
{
    Mat src, dst;
    Mat kernel;
    int ksize = 0;
    Mat s_down;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "result image";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow(INPUT_WIN, s_down);

    //Robert X方向滤波
    Mat kernel_x = (Mat_(2, 2) << 1, 0, 0, -1);
    filter2D(src, dst, -1, kernel_x, Point(-1, -1), 0.0);
    pyrDown(dst, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("Robert X方向", s_down);

    //Robert Y方向滤波
    Mat ying;
    Mat kernel_y = (Mat_(2, 2) << 0,1,-1,0);
    filter2D(src, ying, -1, kernel_y, Point(-1, -1), 0.0);
    pyrDown(ying, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("Robert Y方向", s_down);

    //Sobel X方向滤波
    Mat sobel_x;
    Mat kernel_xx = (Mat_(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
    filter2D(src, sobel_x, -1, kernel_xx, Point(-1, -1), 0.0);
    pyrDown(sobel_x, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("Sobel X方向", s_down);

    //Sobel Y方向滤波
    Mat sobel_y;
    Mat kernel_yy = (Mat_(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
    filter2D(src, sobel_y, -1, kernel_yy, Point(-1, -1), 0.0);
    pyrDown(sobel_y, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("Sobel Y方向", s_down);

    //拉普拉斯算子滤波
    Mat LOG_y;
    Mat kernel_LOG = (Mat_(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
    filter2D(src, LOG_y, -1, kernel_LOG, Point(-1, -1), 0.0);
    pyrDown(LOG_y, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("拉普拉斯算子滤波", s_down);

    /* //自定义滤波
    int c = 0;
    int index = 0;
    Mat dst_z;
    while (true)
    {
        c = waitKey(500);
        if ((char)c == 27)//ESC键
        {
            break;
        }
        ksize = 4 + (index % 8) * 2 + 1;
        Mat kernel_z = Mat::ones(Size(ksize, ksize), CV_32F) / (float)(ksize *ksize);
        filter2D(src, dst_z, -1, kernel_z, Point(-1, -1));
        index++;
        //imshow("自定义滤波", dst_z);
    }
    */
    waitKey(0);
    return 0;
}

P17 图片边框效果处理
# include
# include
# include


using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, dst;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "Border Demo";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_WIN, src);

    int top = (int)(0.05*src.rows);
    int bottom = (int)(0.05*src.rows);
    int left = (int)(0.05*src.cols);
    int right = (int)(0.05*src.cols);
    RNG rng(12345);
    int borderType = BORDER_DEFAULT;

    int c = 0;
    while (true)
    {
        c = waitKey(500);
        if ((char)c == 27)//ESC键
        {
            break;
        }
        if ((char)c == 'r')//r键
        {
            borderType = BORDER_REPLICATE;
        }
        else if ((char)c == 'v')//v键
        {
            borderType = BORDER_WRAP;
        }
        else if ((char)c == 'c')//c键,效果很漂亮
        {
            borderType = BORDER_CONSTANT;
        }

        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        copyMakeBorder(src, dst, top, bottom, left, right, borderType, color);
        imshow(OUTPUT_WIN, dst);
            
    }
    waitKey(0);
    return 0;
}

P18 Sobel算子、Scharr算子边缘检测

# include
# include
# include


using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, dst;
    Mat s_down;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    char OUTPUT_WIN[] = "sobel-Demo";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    //namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow(INPUT_WIN, s_down);

    Mat gray_src;
    GaussianBlur(src, dst, Size(3, 3), 0, 0);
    cvtColor(dst, gray_src, CV_BGR2GRAY);//将彩色图像转换为灰度图像
    pyrDown(gray_src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("灰度图像", s_down);

    Mat xgrad, ygrad;//x,y方向上的sobel边缘检测
    Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
    Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
    convertScaleAbs(xgrad, xgrad);
    convertScaleAbs(ygrad, ygrad);

    pyrDown(xgrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("xSobel算子结果", s_down);
    pyrDown(ygrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("ySobel算子结果", s_down);


    Mat xygrad = Mat(xgrad.size(), xgrad.type());
    int width = xgrad.cols;
    int height = ygrad.rows;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            int xg = xgrad.at(row, col);
            int yg = ygrad.at(row, col);
            int xy = xg + yg;
            xygrad.at(row, col) = xy;
        }
    }
    addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
    pyrDown(xygrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("xySobel算子结果", s_down);//x和y共同方向上的sobel,也即xygrad


    Mat x_grad, y_grad;//x,y方向上的Scharr边缘检测
    Scharr(gray_src, x_grad, CV_16S, 1, 0, 3);
    Scharr(gray_src, y_grad, CV_16S, 0, 1, 3);
    convertScaleAbs(x_grad, x_grad);
    convertScaleAbs(y_grad, y_grad);

    pyrDown(x_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("xScharr算子结果", s_down);
    pyrDown(y_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("yScharr算子结果", s_down);


    Mat xy_grad = Mat(x_grad.size(), x_grad.type());
    int width_ = x_grad.cols;
    int height_ = y_grad.rows;
    for (int row = 0; row < height_; row++)
    {
        for (int col = 0; col < width_; col++)
        {
            int x_g = x_grad.at(row, col);
            int y_g = y_grad.at(row, col);
            int x_y = x_g + y_g;
            xy_grad.at(row, col) = x_y;
        }
    }
    addWeighted(x_grad, 0.5, y_grad, 0.5, 0, xy_grad);
    pyrDown(xy_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("xyScharr算子结果", s_down);//x和y共同方向上的Scharr,也即xyScharr


    waitKey(0);
    return 0;
}

P19拉普拉斯边缘检测算子2021/1/6

# include
# include
# include


using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, dst;
    Mat s_down;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_WIN[] = "input image";
    //char OUTPUT_WIN[] = "Laplaiane Result";
    namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
    //namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
    pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow(INPUT_WIN, s_down);

    
    Mat gray_src, edge_image;
    GaussianBlur(src, dst, Size(3, 3), 0, 0);//高斯滤波
    cvtColor(dst, gray_src, CV_BGR2GRAY);//将彩色图像转换成灰度图像

    Laplacian(gray_src, edge_image, CV_16S, 3);//拉普拉斯检测
    convertScaleAbs(edge_image, edge_image);//取绝对值
    pyrDown(edge_image, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("单纯的拉普拉斯边缘检测", s_down);

    threshold(edge_image, edge_image, 0, 255, THRESH_OTSU | THRESH_BINARY);//阈值操作
    namedWindow("阈值后的拉普拉斯边缘检测", CV_WINDOW_AUTOSIZE);
    pyrDown(edge_image, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
    imshow("阈值后的拉普拉斯边缘检测", s_down);

    waitKey(0);
    return 0;
}

20 Canny算子边缘检测

# include
# include
# include


using namespace cv;
Mat src, dst;
Mat s_down;
Mat gray_src;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** agrv)
{
    
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_TITLE[] = "input image";
    namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_TITLE, src);

    cvtColor(src, gray_src, CV_BGR2GRAY);
    createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
    Canny_Demo(0, 0);


    waitKey(0);
    return 0;
}
void Canny_Demo(int, void*)
{
    Mat edge_output;
    blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
    Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);

    dst.create(src.size(), src.type());
    src.copyTo(dst, edge_output);
    imshow(OUTPUT_TITLE, dst);

}

P21霍夫变换-直线
# include
# include
# include


using namespace cv;
using namespace std;
int main(int argc, char** agrv)
{
    Mat src, src_gray, dst;
    
    src = imread("C:/Users/25503/Desktop/555.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_TITLE[] = "input image";
    char OUTPUT_TITLE[] = "hough-line-detection";
    namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_TITLE, src);

    //extract edge
    Canny(src, src_gray, 150, 200);
    cvtColor(src_gray, dst, CV_GRAY2BGR);
    imshow("edge image", src_gray);

    vector plines;
    HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 10, 0, 10);//直线检测
    Scalar color = Scalar(0, 0, 255);//直线标记红色
    for (size_t i = 0; i < plines.size(); i++)
    {
        Vec4f hline = plines[i];
        line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);

    }
    imshow(OUTPUT_TITLE, dst);

    waitKey(0);
    return 0;
}

P22霍夫圆变换

# include
# include
# include


using namespace cv;
using namespace std;
int main(int argc, char** agrv)
{
    Mat src, src_gray, dst;
    
    src = imread("C:/Users/25503/Desktop/666.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_TITLE[] = "input image";
    char OUTPUT_TITLE[] = "hough-circle-detection";
    namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_TITLE, src);

    //中值滤波
    Mat noutput;
    medianBlur(src, noutput, 3);
    cvtColor(noutput, noutput, CV_BGR2GRAY);

    //霍夫圆检测
    vector pcircles;
    HoughCircles(noutput, pcircles, CV_HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
    src.copyTo(dst);
    for (size_t i = 0; i < pcircles.size(); i++)
    {
        Vec3f cc = pcircles[i];
        circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);
        circle(dst, Point(cc[0], cc[1]), 2, Scalar(198, 23, 155), 2, LINE_AA);

    }
    imshow(OUTPUT_TITLE, dst);
    waitKey(0);
    return 0;
}

P23像素重映射(cv_remap)左边的跑到右边,右边的跑到左边
P24直方图均衡化(提高图像对比度)

# include
# include
# include


using namespace cv;
int main(int argc, char** agrv)
{
    Mat src, src_gray, dst;
    src = imread("C:/Users/25503/Desktop/666.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    cvtColor(src, src, CV_BGR2GRAY);
    equalizeHist(src, dst);
    char INPUT_TITLE[] = "input image";
    char OUTPUT_TITLE[] = "hough-circle-detection";
    namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);

    imshow(INPUT_TITLE, src);
    imshow(OUTPUT_TITLE, dst);
    waitKey(0);
    return 0;
}

P25直方图的计算
# include
# include
# include

using namespace std;
using namespace cv;
int main(int argc, char** agrv)
{
    Mat src;
    src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    char INPUT_TITLE[] = "input image";
    char OUTPUT_TITLE[] = "historgram-demo";
    namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_TITLE, src);
    
    //分通道显示
    vector bgr_planes;
    split(src, bgr_planes);
    imshow("single channel demo", bgr_planes[0]);

    //计算直方图
    int histSize = 256;
    float range[] = { 0,256 };
    const float *histRanges = { range };
    Mat b_hist, g_hist, r_hist;
    calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
    calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
    calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);

    //归一化
    int hist_h = 400;
    int hist_w = 512;
    int bin_w = hist_w / histSize;
    Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
    normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());

    //render histogram chart
    for (int i = 1; i < histSize; i++)
    {
        line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at(i - 1))), Point((i)*bin_w, hist_h - cvRound(b_hist.at(i))), Scalar(255, 0, 0), 2, LINE_AA);
        line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at(i - 1))), Point((i)*bin_w, hist_h - cvRound(g_hist.at(i))), Scalar(0, 255, 0), 2, LINE_AA);
        line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at(i - 1))), Point((i)*bin_w, hist_h - cvRound(r_hist.at(i))), Scalar(0, 0, 255), 2, LINE_AA);
    }
    imshow(OUTPUT_TITLE, histImage);
    waitKey(0);
    return 0;
}

P26直方图比较

P27直方图反向投影
# include
# include
# include

using namespace std;
using namespace cv;

Mat src; Mat hsv; Mat hue;
int bins = 12;
void Hist_And_Backprojection(int, void*);
int main(int argc, char** agrv)
{
    Mat src;
    src = imread("C:/Users/25503/Desktop/777.jpg");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }

    const char* window_image = "input image";
    namedWindow(window_image, CV_WINDOW_AUTOSIZE);
    namedWindow("BackProj", CV_WINDOW_AUTOSIZE);
    namedWindow("Histogram", CV_WINDOW_AUTOSIZE);

    cvtColor(src, hsv, CV_BGR2HSV);
    hue.create(hsv.size(), hsv.depth());
    int nchannels[] = { 0,0 };
    mixChannels(&hsv, 1, &hue, 1, nchannels, 1);

    createTrackbar("Histogram Bins:", window_image, &bins, 180, Hist_And_Backprojection);//绘制标尺
    Hist_And_Backprojection(0, 0);//直方图反向投影


    imshow(window_image, src);
    waitKey(0);
    return 0;
}

void Hist_And_Backprojection(int, void*)
{
    float range[] = { 0,180 };
    const float *histRanges = { range };
    Mat h_hist;
    calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
    normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

    Mat backPrjImage;
    calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
    imshow("BackProj", backPrjImage);

    int hist_h = 400;
    int hist_w = 400;
    Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
    int bin_w = (hist_w / bins);
    for (int i = 1; i < bins; i++)
    {
        rectangle(histImage, Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at(i - 1)*(400 / 255)))), Point(i*bin_w, (hist_h - cvRound(h_hist.at(i)*(400 / 255)))), Scalar(0, 0, 255), -1);

    }
    imshow("Histogram", histImage);
    return;
}

P28模板匹配1//2021/1/8****
# include
# include
#include

using namespace std;
using namespace cv;

Mat src, temp, dst;
int match_method = CV_TM_SQDIFF;
int max_track = 5;

const char* INPUT_T = "input image";
const char* OUTPUT_T = "result image";
const char* match_t = "template match-demo";
void Match_Demo(int, void*);

int main(int argc, char**agrv)
{
    src = imread("C:/Users/25503/Desktop/888.png");//原图像
    temp = imread("C:/Users/25503/Desktop/999.png");//模板图像(原图像子图像)
    if (src.empty() || temp.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow(INPUT_T, CV_WINDOW_AUTOSIZE);
    namedWindow(OUTPUT_T, CV_WINDOW_AUTOSIZE);
    namedWindow(match_t, CV_WINDOW_AUTOSIZE);
    imshow(INPUT_T, temp);
    const char* trackbar_title = "Match Algo Type";
    createTrackbar(trackbar_title, OUTPUT_T, &match_method, max_track, Match_Demo);
    Match_Demo(0, 0);


    waitKey(0);
    return 0;
}
void Match_Demo(int, void*)
{
    int width = src.cols - temp.cols + 1;
    int height = src.rows - temp.rows + 1;
    Mat result(width, height, CV_32FC1);

    matchTemplate(src, temp, result, match_method, Mat());
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    Point minLoc;
    Point maxLoc;
    double min, max;
    src.copyTo(dst);
    Point temLoc;
    minMaxLoc(result, &min, &max, &minLoc,&maxLoc, Mat());
    if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)

    {
        temLoc = minLoc;
    }
    else
    {
        temLoc = maxLoc;
    }
    //绘制矩形框
    rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);
    rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);

    imshow(OUTPUT_T, result);
    imshow(match_t, dst);

}

P28模板匹配2//2021/1/8****

#include
#include
#include
#include
#include

using namespace std;
using namespace cv;
/**********************************************************
 *
 * input:
 * argc-----current mass center point
 * argv-----previous mass center point
 *
 **********************************************************/
int main(int argc, char **argv)
{
    Mat pFrame;//read frame from video
    Mat pFrameGray;
    VideoCapture pCapture;
    pCapture.open("./plane.mov");
    if (!pCapture.isOpened())
    {
        cout << "open video error" << endl;
        return -1;
    }

    Mat temp;
    temp = imread("./plane.png", 0);//read a gray template
    if (!temp.data)
    {
        cout << "read template pic error" << endl;
        return -1;
    }

    namedWindow("template tracking");
    moveWindow("template tracking", 100, 100);

    Mat result;//save template match result
    while (1)
    {
        pCapture.read(pFrame);//read a frame from video
        cvtColor(pFrame, pFrameGray, CV_BGR2GRAY);

        matchTemplate(pFrameGray, temp, result, TM_SQDIFF);

        //location
        double minValue;
        double maxValue;
        //location point
        Point minLocP;
        Point maxLocP;
        //match locat
        minMaxLoc(result, &minValue, &maxValue, &minLocP, &maxLocP, Mat());

        rectangle(pFrame, Rect(minLocP.x, minLocP.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8, 0);

        imshow("template tracking", pFrame);
        waitKey(33);

    }
    return 0;
}

P29轮廓发现***
# include
# include
# include

using namespace std;
using namespace cv;

Mat src, dst;
const char* output_win = "findcontours-demo";
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Contours(int, void*);
int main(int agrc, char** agrv)
{
    src = imread("C:/Users/25503/Desktop/11.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input-image", CV_WINDOW_AUTOSIZE);
    namedWindow(output_win, CV_WINDOW_AUTOSIZE);
    imshow("input-image", src);
    cvtColor(src, src, CV_BGR2GRAY);

    const char* trackbar_title = "Threshold Value";
    createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
    Demo_Contours(0, 0);

    waitKey(0);
    return 0;
}
void Demo_Contours(int, void*)
{
    Mat canny_output;
    vector> contours;
    vector hierachy;
    Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
    findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//发现轮廓

    dst = Mat::zeros(src.size(), CV_8UC3);
    RNG rng(12345);
    for (size_t i = 0; i < contours.size(); i++)
    {
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//轮廓颜色
        drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));//绘制轮廓

    }
    imshow(output_win, dst);
}

P30凸包

P31轮廓周围绘制矩形和圆形框绘制*****
# include
# include
# include

using namespace std;
using namespace cv;

Mat src, gray_src,drawImg;
const char* output_win = "rectangle-demo";
int threshold_v = 170;
int threshold_max = 255;
RNG rng(12345);
void Contours_Callback(int, void*);
int main(int agrc, char** agrv)
{
    src = imread("C:/Users/25503/Desktop/11.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    cvtColor(src, gray_src, CV_BGR2GRAY);
    blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));

    const char* source_win = "input image";
    namedWindow(source_win, CV_WINDOW_AUTOSIZE);
    namedWindow(output_win, CV_WINDOW_AUTOSIZE);
    imshow(source_win, src);

    createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);
    Contours_Callback(0, 0);

    waitKey(0);
    return 0;
}
void Contours_Callback(int, void*)
{
    Mat binary_output;
    vector> contours;
    vector hierachy;
    threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
    imshow("binary image", binary_output);
    findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));


    vector> contours_ploy(contours.size());
    vector ploy_rects(contours.size());
    vector ccs(contours.size());
    vector radius(contours.size());

    vector minRects(contours.size());
    vector myellipse(contours.size());


    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
        ploy_rects[i] = boundingRect(contours_ploy[i]);
        minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);
        if (contours_ploy[i].size() > 5)
        {
            myellipse[i] = fitEllipse(contours_ploy[i]);
            minRects[i] = minAreaRect(contours_ploy[i]);
        }
    
    }


    //draw it
    src.copyTo(drawImg);
    Point2f pts[4];
    for (size_t t = 0; t < contours.size(); t++)
    {
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        //rectangle(drawImg, ploy_rects[t], color, 2, 8);
        //circle(drawImg, ccs[t], radius[t], color, 2, 8);
        if (contours_ploy[t].size() > 5)
        {
            ellipse(drawImg, myellipse[t], color, 2, 8);
            minRects[t].points(pts);
            for (int r = 0; r < 4; r++)
            {
                line(drawImg, pts[r], pts[(r + 1) % 4], color, 2, 8);
            }

        }
    }

    imshow("矩形框+圆形框", drawImg);
    return;

}

P32图像矩-计算弧长、面积(适用于多个细胞面积计算)*****
# include
# include
# include

using namespace std;
using namespace cv;

Mat src, gray_src;
const char* output_win = "image moents demo";
int threshold_value = 80;
int threshold_max = 255;
RNG rng(12345);
void Dem0_Moment(int, void*);
int main(int agrc, char** agrv)
{
    src = imread("C:/Users/25503/Desktop/888.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    cvtColor(src, gray_src, CV_BGR2GRAY);
    GaussianBlur(gray_src, gray_src, Size(3, 3), 0,0);

    const char* input_win = "input image";
    namedWindow(input_win, CV_WINDOW_AUTOSIZE);
    namedWindow(output_win, CV_WINDOW_AUTOSIZE);
    imshow(input_win, src);

    createTrackbar("Threshold Value:", output_win, &threshold_value, threshold_max, Dem0_Moment);
    Dem0_Moment(0, 0);

    waitKey(0);
    return 0;
}
void Dem0_Moment(int, void*)
{
    Mat canny_output;
    vector> contours;
    vector hierachy;

    Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);
    findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    vector contours_moments(contours.size());
    vector ccs(contours.size());
    for (size_t i = 0; i < contours.size(); i++)
    {
        contours_moments[i] = moments(contours[i]);
        ccs[i] = Point(static_cast(contours_moments[i].m10 / contours_moments[i].m00), static_cast(contours_moments[i].m01 / contours_moments[i].m00));

    }
    Mat drawImg;
    src.copyTo(drawImg);
    for (size_t i = 0; i < contours.size(); i++)
    {
        if (contours[i].size() < 30)//直径小于30的不显示,数字30可以修改
        {
            continue;
        }
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        printf("center point x: %.2f y: %.2f\n", ccs[i].x, ccs[i].y);
        printf("contours %d area :%.2f  arc length :%.2f\n", i, contourArea(contours[i]), arcLength(contours[i], true));
        drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
        circle(drawImg, ccs[i], 2, color, 2, 8);
    }
    imshow(output_win, drawImg);
    return;

}

P33点多边形测试-测试一个点或者多个点是否在多边形内部、边缘或者外部

# include
# include
#include

using namespace std;
using namespace cv;

int main(int agrc, char** agrv)
{
    const int r = 100;
    Mat src = Mat::zeros(r * 4, r * 4, CV_8UC1);

    vectorvert(6);
    vert[0] = Point(3 * r / 2, static_cast(1.34*r));
    vert[1] = Point(1 *r, 2 * r);
    vert[2] = Point(3 * r / 2, static_cast(2.866*r));
    vert[3] = Point(5 * r / 2, static_cast(2.866*r));
    vert[4] = Point(3 * r ,2 *r);
    vert[5] = Point(5 * r / 2, static_cast(1.34*r));

    for (int i = 0; i < 6; i++)
    {
        line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);
    }

    vector> contours;
    vector hierachy;
    Mat csrc;
    src.copyTo(csrc);
    findContours(csrc, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);

    for (int row = 0; row < raw_dist.rows; row++)
    {
        for (int col = 0; col < raw_dist.cols; col++)
        {
            double dist = pointPolygonTest(contours[0], Point2f(static_cast(col), static_cast(row)), true);
            raw_dist.at(row, col) = static_cast(dist);
        }
    }

    double minValue, maxValue;
    minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());
    Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
    for (int row = 0; row < drawImg.rows; row++)
    {
        for (int col = 0; col < drawImg.cols; col++)
        {
            float dist = raw_dist.at(row, col);
            if (dist > 0)
            {
                drawImg.at(row, col)[0] = (uchar)(abs(1.0 - dist / maxValue) * 255);
            }
            else if (dist < 0)
            {
                drawImg.at(row, col)[2] = (uchar)(abs(1.0 - dist / minValue) * 255);
            }
            else
            {
                drawImg.at(row, col)[0] = (uchar)(abs(255 - dist));
                drawImg.at(row, col)[1] = (uchar)(abs(255 - dist));
                drawImg.at(row, col)[2] = (uchar)(abs(255 - dist));
            }
        }
    }


    const char* output_win = "point polygon test demo";
    char input_win[] = "input image";
    namedWindow(input_win, CV_WINDOW_AUTOSIZE);
    namedWindow(output_win, CV_WINDOW_AUTOSIZE);

    imshow(input_win, src);
    imshow(output_win, drawImg);

    waitKey(0);
    return 0;

}

P34-P35基于距离变换与分水岭的图像分割*****

//基于距离变换和分水岭的图像分割(image segmentation)
//图像分割的目标是将图像中像素根据一定的规则分为若干(N)个cluster集合,每个集合包含一类像素。
//步骤:1.将白色背景变成黑色-目的是为后面的变换做准备
//2. 使用filter2D与拉普拉斯算子实现图像对比度提高,sharp
//3. 转为二值图像通过threshold
//4. 距离变换
//5. 对距离变换结果进行归一化到[0~1]之间
//6. 使用阈值,再次二值化,得到标记
//7. 腐蚀得到每个Peak - erode
//8.发现轮廓 – findContours
//9. 绘制轮廓 - drawContours
//10.分水岭变换 watershed
//11. 对每个分割区域着色输出结果

#include
#include
#include

using namespace std;
using namespace cv;

int main(int argc, char*argv)
{
    Mat src;
    src = imread("C:/Users/25503/Desktop/888.png");
    if (!src.data)
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input", CV_WINDOW_AUTOSIZE);
    imshow("input", src);

    //将白色背景变成黑色-目的是为后面的变换做准备
    for (int row = 0; row < src.rows; row++)
    {
        for (int col = 0; col < src.cols; col++)
        {
            if (src.at(row, col)[0] > 200 && src.at(row, col)[1] > 200 && src.at(row, col)[2] > 200)
            {
                src.at(row, col)[0] = 0;
                src.at(row, col)[1] = 0;
                src.at(row, col)[2] = 0;
            }
        }
    }
    const char*input = "change backgroud image";
    namedWindow(input, CV_WINDOW_AUTOSIZE);
    imshow(input, src);

    //使用filter2D与拉普拉斯算子实现图像对比度提高,sharp
    Mat imgLaplance;
    Mat sharp = src;
    Mat kernel = (Mat_(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
    filter2D(sharp, imgLaplance, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
    src.convertTo(sharp, CV_32F);
    Mat imgResult = sharp - imgLaplance;

    //显示
    imgResult.convertTo(imgResult, CV_8UC3);
    imgLaplance.convertTo(imgLaplance, CV_8UC3);
    namedWindow("Sharp image", CV_WINDOW_AUTOSIZE);
    imshow("Sharp image", imgResult);
    // src = resultImg; // copy back

    //binary image转为二值图像通过threshold
    Mat binaryImag;
    cvtColor(src, binaryImag, CV_BGR2GRAY);
    threshold(binaryImag, binaryImag, 40, 255, THRESH_OTSU | THRESH_BINARY);
    namedWindow("binary image", CV_WINDOW_AUTOSIZE);
    imshow("binary image", binaryImag);

    //距离变换(distance transform )
    Mat distImg;
    distanceTransform(binaryImag, distImg, DIST_L1, 3, 5);
    //cv::distanceTransform(InputArray  src, OutputArray dst,  OutputArray  labels,  int  distanceType,  int maskSize,  int labelType=DIST_LABEL_CCOMP)
    //distanceType = DIST_L1 / DIST_L2,
    //maskSize = 3x3, 最新的支持5x5,推荐3x3、
    //labels离散维诺图输出
    //dst输出8位或者32位的浮点数,单一通道,大小与输入图像一致

    //对距离变换结果进行归一化到[0~1]之间
    normalize(distImg, distImg, 0, 1, NORM_MINMAX);
    imshow("distance image", distImg);

    //使用阈值,再次二值化,得到标记(binary again)
    threshold(distImg, distImg, .2, 1, THRESH_BINARY);

    //腐蚀得到每个Peak - erode
    Mat kernel1 = Mat::ones(13, 13, CV_8UC1);
    erode(distImg, distImg, kernel1, Point(-1, -1));
    imshow("distance binary image", distImg);

    // markers (发现轮廓 – findContours)
    Mat dist_8u;
    distImg.convertTo(dist_8u, CV_8U);
    vector> contours;
    findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

    // create makers(绘制轮廓 - drawContours)
    Mat markers = Mat::zeros(src.size(), CV_32SC1);
    for (size_t i = 0; i < contours.size(); i++) {
        drawContours(markers, contours, static_cast(i), Scalar::all(static_cast(i) + 1), -1);
    }
    circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);
    imshow("my markers", markers * 1000);

    // perform watershed(基于浸泡理论实现 )
    watershed(src, markers);
    Mat mark = Mat::zeros(markers.size(), CV_8UC1);
    markers.convertTo(mark, CV_8UC1);
    //src.convertTo(dst, type, scale, shift)
    //dst:目的矩阵;
    //type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用 - 1)则输出矩阵和输入矩阵类型相同;
    //scale : 比例因子;
    //shift:将输入数组元素按比例缩放后添加的值;
    bitwise_not(mark, mark, Mat());
    imshow("watershed image", mark);


    // generate random color
    vector colors;
    for (size_t i = 0; i < contours.size(); i++) {
        int r = theRNG().uniform(0, 255);
        int g = theRNG().uniform(0, 255);
        int b = theRNG().uniform(0, 255);
        colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
    }

    // fill with color and display final result(对每个分割区域着色输出结果)
    Mat dst = Mat::zeros(markers.size(), CV_8UC3);
    for (int row = 0; row < markers.rows; row++) {
        for (int col = 0; col < markers.cols; col++) {
            int index = markers.at(row, col);
            if (index > 0 && index <= static_cast(contours.size())) {
                dst.at(row, col) = colors[index - 1];
            }
            else {
                dst.at(row, col) = Vec3b(0, 0, 0);
            }
        }
    }
    imshow("Final Result", dst);

    waitKey(0);
    return 0;
}


P36-P37特征提取与检测实战概述2021/1/9
P38 -P39 Harris角点检测

#include
#include
#include

using namespace cv;
using namespace std;

void Harris_demo(int, void*);
int thres_value = 130;
int thres_Max = 255;
Mat src, gray_src;
const char* outputTitle = "output title";
int main(int argc, char** argv)
{
    src = imread("C:/Users/25503/Desktop/888.png");
    if (src.empty())
    {
        cout << "图片为空" << endl;
        return -1;
    }
    cvtColor(src, gray_src, CV_BGR2GRAY);
    namedWindow(outputTitle, CV_WINDOW_AUTOSIZE);
    createTrackbar("Harris", outputTitle, &thres_value, thres_Max, Harris_demo);
    Harris_demo(0, 0);
    imshow("input title", src);
    waitKey(0);
    return 0;


}

void Harris_demo(int, void *)
{
    Mat dst, norm_dst;
    dst = Mat::zeros(gray_src.size(), CV_32FC1);


    cornerHarris(gray_src, dst, 2, 3, 0.04, BORDER_DEFAULT);
    normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    convertScaleAbs(norm_dst, norm_dst);
    Mat resultImg = src.clone();

    for (int row = 0; row < resultImg.rows; row++)
    {
        uchar* currentRow = norm_dst.ptr(row);
        for (int col = 0; col < resultImg.cols; col++)
        {

            int value = (int)*currentRow;

            if (value > thres_value)
            {
                circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
            }
            currentRow++;

        }
    }

    imshow(outputTitle, resultImg);

}


P40 Shi-Tomasi角点检测

# include
# include

using namespace cv;
using namespace std;

int num_corners = 25;
int max_corners = 500;
const char* output_title = "ShiTomasi Detector";
void ShiTomasi_Demo(int, void*);
Mat src, gray_src;
RNG rng(12345);

int main(int argc, char* agrv)
{

    src = imread("C:/Users/25503/Desktop/110.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    createTrackbar("Num Corners", output_title, &num_corners, max_corners, ShiTomasi_Demo);
    ShiTomasi_Demo(0, 0);

    waitKey(0);
    return 0;

}

void ShiTomasi_Demo(int, void*)
{
    if (num_corners < 5)
    {
        num_corners = 5;
    }
    vector corners;
    double qualityLevel = 0.01;
    double minDistance = 10;
    int blockSize = 3;
    bool useHarris = false;
    double k = 0.04;
    Mat resultImg = gray_src.clone();
    cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
    goodFeaturesToTrack(gray_src, corners, num_corners, qualityLevel, minDistance, Mat(), blockSize, useHarris, k);
    printf("number of Detected Corners:%d\n", corners.size());

    for (size_t t = 0; t < corners.size(); t++)
    {
        circle(resultImg, corners[t], 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);

    }
    imshow(output_title, resultImg);

}

P41-P42自定义角点检测器

#include
#include
#include

using namespace cv;
using namespace std;

Mat src, gray_src;
int current_value = 30;
int Max_value = 100;

double minVal;
double maxVal;

Mat harris_res, harris_src;
void custom_corner_harris(int, void*);
const char* output_title = "output title";
int main(int argc, char** argv)
{
    src = imread("C:/Users/25503/Desktop/110.png");
    if (src.empty())
    {
        cout << "the image could not found..." << endl;
        return -1;
    }
    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    harris_src = Mat::zeros(src.size(), CV_32FC(6));
    harris_res = Mat::zeros(src.size(), CV_32FC1);
    imshow("input title", src);
    // 计算特征值

    int blocksize = 3;
    double k = 0.04;
    int ksize = 3;   //Sobel算子当中的核大小,只能取1、3、5、7
    cornerEigenValsAndVecs(gray_src, harris_src, blocksize, ksize, BORDER_DEFAULT);

    //计算响应
    for (int row = 0; row < harris_src.rows; row++)
    {
        for (int col = 0; col < harris_src.cols; col++)
        {
            double lamda1 = harris_src.at(row, col)[0];
            double lamda2 = harris_src.at(row, col)[1];
            harris_res.at(row, col) = static_cast(lamda1 * lamda2 - k * pow((lamda1 + lamda2), 2));
        }
    }
    minMaxLoc(harris_res, &minVal, &maxVal, 0, 0, Mat());
    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    createTrackbar("custom bar", output_title, ¤t_value, Max_value, custom_corner_harris);
    custom_corner_harris(0, 0);

    waitKey(0);
    return 0;
}

void custom_corner_harris(int, void*)
{
    if (current_value < 10)
    {
        current_value = 10;
    }
    //cvtColor(gray_src, gray_src, COLOR_GRAY2BGR);
    Mat resultImg = gray_src.clone();
    cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
    RNG rng(12345);
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    float t = static_cast(minVal + (((double)current_value) / Max_value)*(maxVal - minVal));//阈值,如果大于某个百分比,则响应
    for (int row = 0; row < src.rows; row++)
    {
        for (int col = 0; col < src.cols; col++)
        {
            float v = harris_res.at(row, col);
            if (v > t)
            {
                circle(resultImg, Point(col, row), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
            }
        }
    }
    printf("corner num:%d\n", current_value);
    imshow(output_title, resultImg);
}


P43 亚像素级别角点检测-目的是提高检测的准确性(可以具体到小数点后三位)项目常用于提高精度*******

#include
#include
#include

using namespace std;
using namespace cv;

Mat src, gray_src;
int maxCorner = 20;
int max_value = 200;

const char* output_title = "subpixel window";
void subpixel(int, void*);
int main(int argc, char** argv)
{
    src = imread("C:/Users/25503/Desktop/110.png");
    if (!src.data)
    {
        cout << "图片未找到" << endl;
        return -1;
    }
    cvtColor(src, gray_src, CV_BGR2GRAY);
    imshow("input title", src);
    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    createTrackbar("subpixel num", output_title, &maxCorner, max_value, subpixel);
    subpixel(0, 0);
    waitKey(0);
    return 0;

}

void subpixel(int, void *)
{
    if (maxCorner < 5)
    {
        maxCorner = 5;
    }
    vectorcorners;
    goodFeaturesToTrack(gray_src, corners, maxCorner, 0.01, 10, Mat(), 3, false, 0.04);
    Mat resultImg = src.clone();
    for (size_t i = 0; i < corners.size(); i++)
    {
        circle(resultImg, corners[i], 2, Scalar(0, 0, 255), 2, 8, 0);
    }
    cout << "corner num: " << corners.size() << endl;
    imshow(output_title, resultImg);
    Size size = Size(5, 5);//最多只能取到5
    //迭代算法的终止准则,该类变量需要3个参数,一个是类型,第二个参数为迭代的最大次数,最后一个是特定的阈值
    TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.01);
    cornerSubPix(gray_src, corners, size, Size(-1, -1), tc);
    //这里的corner重新变了,变成cornerSubPix里的corners了
    for (size_t t = 0; t < corners.size(); t++)
    {
        cout << t + 1 << ".pixel[x,y]= " << corners[t].x << "," << corners[t].y << endl;

    }
    return;

}

P44 -P45 SURF特征检测--失败

#include
#include
#include
#include
using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;

Mat g_srcImage, g_grayImage, g_keyPointImage;

int main()
{
    g_srcImage = cv::imread("curry_dlt.jpg", 0);
    if (g_srcImage.empty())
    {
        printf("read image fail\n");
        return -1;
    }
    imshow("g_srcImage", g_srcImage);
    int minHessian = 400;

    // SURF特征检测
    vector keyPoints;
    Ptr detector = SURF::create(minHessian); //创建一个检测器
    detector->detect(g_srcImage, keyPoints, Mat());

    // 绘制关键点
    g_keyPointImage = g_srcImage.clone();
    drawKeypoints(g_srcImage, keyPoints, g_keyPointImage, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
    
    imshow("g_keyPointImage", g_keyPointImage);    
    waitKey(0);
    return 0;
}

P46-P47 SIFT特征检测--失败

#include
#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

Mat src;
int main(int argc, char** argv)
{
    src = imread("D:/test/src.png",IMREAD_GRAYSCALE);
    if (!src.data)
    {
        cout << "图片未找到" << endl;
        return -1;
    }
    imshow("input title", src);
    int numfeature = 400;
    Ptrdetector = SIFT::create(numfeature);//与SURF一样,剩余的取默认值
    vectorkeypoints;
    detector->detect(src, keypoints, Mat());
    Mat resultImg;
    drawKeypoints(src, keypoints, resultImg, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
    imshow("SIFT keypoint", resultImg);
    waitKey(0);
    return 0;

}

P48-P49 HOG特征检测--框选择

#include
#include
using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/1122.png");
    if (src.empty())
    {
        namedWindow("input image", CV_WINDOW_AUTOSIZE);
        imshow("input image", src);

    }

    Mat dst, dst_gray;
    resize(src, dst, Size(64, 128));
    cvtColor(dst, dst_gray, COLOR_BGR2GRAY);
    //HOGDescriptor detector(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
    //vector descriptors;
    //vector locations;
    //printf("number of HOG descriptors:%d", descriptors.size());

    HOGDescriptor hog = HOGDescriptor();
    hog.setSVMDetector(hog.getDefaultPeopleDetector());

    vector foundLocations;
    hog.detectMultiScale(src, foundLocations, 0, Size(8, 8), Size(32, 32), 1.05, 2);
    Mat result = src.clone();
    for (rsize_t t = 0; t < foundLocations.size(); t++)
    {
        rectangle(result, foundLocations[t], Scalar(0, 0, 255), 2, 8, 0);

    }
    namedWindow("HOG SVM Detector Demo", CV_WINDOW_AUTOSIZE);
    imshow("HOG SVM Detector Demo",result);
}

P50-P52LBP特征检测

#include
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat src, dst;
    Mat gray_src;
    src = imread("C:/Users/25503/Desktop/1122.png");
    if (src.empty())
    {
        namedWindow("input image", CV_WINDOW_AUTOSIZE);
        imshow("input image", src);

    }
    const char* output_tt = "LBP Result";
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    namedWindow(output_tt, CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    //convert to gray
    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    int width = gray_src.cols;
    int height = gray_src.rows;

    Mat ibpImage = Mat::zeros(gray_src.rows - 2, gray_src.cols - 2, CV_8UC1);
    for (int row = 1; row < height - 1; row++)
    {
        for (int col = 1; col < width - 1; col++)
        {
            uchar c = gray_src.at(row, col);
            uchar code = 0;
            code |= (gray_src.at(row - 1, col - 1) > c) << 7;
            code |= (gray_src.at(row - 1, col) > c) << 7;
            code |= (gray_src.at(row - 1, col + 1) > c) << 7;
            code |= (gray_src.at(row , col + 1) > c) << 7;
            code |= (gray_src.at(row +1 , col + 1) > c) << 7;
            code |= (gray_src.at(row + 1, col) > c) << 7;
            code |= (gray_src.at(row + 1, col - 1) > c) << 7;
            code |= (gray_src.at(row , col - 1) > c) << 7;
            ibpImage.at(row - 1, col - 1) = code;
        }
    }
    imshow(output_tt, ibpImage);

    waitKey(0);
    return 0;
}

P53 积分图计算

# include
# include

using namespace cv;
int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/1122.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }

    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    Mat sumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_32FC1);
    Mat sqsumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_64FC1);
    integral(src, sumii, sqsumii);

    Mat iiResult;
    normalize(sumii, iiResult, 0, 255, NORM_MINMAX, CV_8UC1, Mat());
    imshow("Integral Image", iiResult);

    waitKey(0);
    return 0;
}


P54 Harris特征检测-基于积分图(后续有相关代码)


P55特征描述子2021/1/12--模板匹配

# include
# include
# include

using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

int main(int agrc, char** agrv)
{
    Mat img1 = imread("C:/Users/25503/Desktop/1122.png",IMREAD_GRAYSCALE);
    Mat img2 = imread("C:/Users/25503/Desktop/110.png", IMREAD_GRAYSCALE);
    if (!img1.data || !img2.data)
    {
        return -1;
    }

    imshow("image1", img1);
    imshow("image2", img2);

    int minHessian = 400;
    Ptrdetector = SURF::create(minHessian);
    vector keypoints_1;
    vector keypoints_2;

    Mat descriptor_1, descriptor_2;
    detector->detectAndCompute(img1, Mat(), keypoints_1, descriptor_1);
    detector->detectAndCompute(img2, Mat(), keypoints_2, descriptor_2);

    BFMatcher matcher;
    vector matches;
    matcher.match(descriptor_1, descriptor_2, matches);

    Mat matchesImg;
    drawMatches(img1, keypoints_1, img2, keypoints_2, matches, matchesImg);
    imshow("Descriptor Demo", matchesImg);


    waitKey(0);
    return 0;
}

P56 FLANN特征匹配(原图像和子图像)失败

#include
#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

//检测计算和绘制时,源图(img1)在前面,目标图像(img2)在后面
Mat img1, img2;
int main(int argc, char**argv)
{
    img1 = imread("C:/Users/25503/Desktop/888.png", 0);
    img2 = imread("C:/Users/25503/Desktop/999.png", 0);


    if (!img1.data || !img2.data)
    {
        cout << "图片为空!" << endl;
        return -1;
    }
    int minHesssion = 400;
    Ptr detector = SURF::create(minHesssion);   //也可以用SIRF,但是效率比SURF低
    vector keypoints_obj;         //存放img1的特征值
    vector keypoints_scene;    //存放img2的特征值
    Mat descript_obj, descript_scene;
    detector->detectAndCompute(img1, Mat(), keypoints_obj, descript_obj);  //检测并计算特征描述子
    detector->detectAndCompute(img2, Mat(), keypoints_scene, descript_scene);

    FlannBasedMatcher fbmatcher;
    vectormatches;
    fbmatcher.match(descript_obj, descript_scene, matches); //特征描述子匹配

    //找出最优特征点
    double minDist = 1000;    //初始化最大最小距离
    double maxDist = 0;

    for (int i = 0; i < descript_obj.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist > maxDist)
        {
            maxDist = dist;
        }
        if (dist < minDist)
        {
            minDist = dist;
        }
    }
    printf("maxDist:%f\n", maxDist);
    printf("minDist:%f\n", minDist);

    vector goodMatches;
    for (int i = 0; i < descript_obj.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist < max(2 * minDist, 0.02)) {
            goodMatches.push_back(matches[i]);
        }
    }
    Mat resultImg;
    drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, resultImg, Scalar::all(-1),
        Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS
    );


    imshow("input image1", img1);
    imshow("input image2", img2);
    imshow("FlannBasedMatcher demo", resultImg);
    waitKey(0);
    return 0;


}


P57 平面对象识别--失败

#include
#include
using namespace cv;
using namespace cv::xfeatures2d;

int main()
{
    Mat src1, src2;
    src1 = imread("E:/image/image/card.jpg");
    src2 = imread("E:/image/image/cards.jpg");
    if (src1.empty() || src2.empty())
    {
        printf("can ont load images....\n");
        return -1;
    }
    imshow("image1", src1);
    imshow("image2", src2);

    int minHessian = 400;
    //选择SURF特征
    Ptrdetector = SURF::create(minHessian);
    std::vectorkeypoints1;
    std::vectorkeypoints2;
    Mat descriptor1, descriptor2;
    //检测关键点并计算描述符
    detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1);
    detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2);

    //基于Flann的描述符匹配器
    FlannBasedMatcher matcher;
    std::vectormatches;
    //从查询集中查找每个描述符的最佳匹配
    matcher.match(descriptor1, descriptor2, matches);
    double minDist = 1000;
    double maxDist = 0;
    for (int i = 0; i < descriptor1.rows; i++)
    {
        double dist = matches[i].distance;
        printf("%f \n", dist);
        if (dist > maxDist)
        {
            maxDist = dist;
        }
        if (dist < minDist)
        {
            minDist = dist;
        }

    }
    //DMatch类用于匹配关键点描述符的
    std::vectorgoodMatches;
    for (int i = 0; i < descriptor1.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist < max(2 * minDist, 0.02))
        {
            goodMatches.push_back(matches[i]);
        }
    }
    Mat matchesImg;
    drawMatches(src1, keypoints1, src2, keypoints2, goodMatches, matchesImg, Scalar::all(-1),
        Scalar::all(-1), std::vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

    std::vectorpoint1, point2;
    for (int i = 0; i < goodMatches.size(); i++)
    {
        point1.push_back(keypoints1[goodMatches[i].queryIdx].pt);
        point2.push_back(keypoints2[goodMatches[i].trainIdx].pt);
    }

    Mat H = findHomography(point1, point2, RANSAC);
    std::vectorcornerPoints1(4);
    std::vectorcornerPoints2(4);
    cornerPoints1[0] = Point(0, 0);
    cornerPoints1[1] = Point(src1.cols, 0);
    cornerPoints1[2] = Point(src1.cols, src1.rows);
    cornerPoints1[3] = Point(0, src1.rows);
    perspectiveTransform(cornerPoints1, cornerPoints2, H);

    //绘制出变换后的目标轮廓,由于左侧为图像src2故坐标点整体右移src1.cols
    line(matchesImg, cornerPoints2[0] + Point2f(src1.cols, 0), cornerPoints2[1] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
    line(matchesImg, cornerPoints2[1] + Point2f(src1.cols, 0), cornerPoints2[2] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
    line(matchesImg, cornerPoints2[2] + Point2f(src1.cols, 0), cornerPoints2[3] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
    line(matchesImg, cornerPoints2[3] + Point2f(src1.cols, 0), cornerPoints2[0] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);

    //在原图上绘制出变换后的目标轮廓
    line(src2, cornerPoints2[0], cornerPoints2[1], Scalar(0, 255, 255), 4, 8, 0);
    line(src2, cornerPoints2[1], cornerPoints2[2], Scalar(0, 255, 255), 4, 8, 0);
    line(src2, cornerPoints2[2], cornerPoints2[3], Scalar(0, 255, 255), 4, 8, 0);
    line(src2, cornerPoints2[3], cornerPoints2[0], Scalar(0, 255, 255), 4, 8, 0);

    imshow("output", matchesImg);
    imshow("output2", src2);

    waitKey();
    return 0;
}

P58-P59  AKAZE局部匹配*******成功

#include
#include
#include

using namespace cv;
using namespace std;

Mat img1, img2;
int main(int argc, char** argv)
{
    img1 = imread("C:/Users/25503/Desktop/888.png", IMREAD_GRAYSCALE);
    img2 = imread("C:/Users/25503/Desktop/999.png", IMREAD_GRAYSCALE);
    if (!img1.data || !img2.data)
    {
        printf("图片未找到...");
        return -1;
    }
    imshow("input box", img1);
    imshow("input box_in_scene", img2);
    double t1 = getTickCount();
    //检测特征点(非线性)
    Ptrdetector = AKAZE::create();
    //Ptrdetector = KAZE::create();//KAZE检测

    //存放描述子
    Mat descriptor_obj, descriptor_scene;

    //img1特征点检测并计算描述子
    vector keypoints_obj;
    detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj);

    //img2特征点检测并计算描述子
    vector keypoints_scene;
    detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);
    double t2 = getTickCount();
    double t = (t2 - t1) * 1000 / getTickFrequency();//结果转化为毫秒
    printf("特征点寻找所花费时间(ms):%f", t);

    //使用FLANN匹配器比较两个关键点的匹配度
    FlannBasedMatcher fbMatcher(new flann::LshIndexParams(20, 10, 2));//用LshIndexParams

    /*这里不能使用FlannBasedMatcher fbMatcher();这条语句,因为它不支持CV_8UC1类型,
    会报错,OpenCv暂时还没有解决这一问题。*/
    //也可以使用暴力匹配(BFMatcher bfmatches;)

    BFMatcher bfmatches;
    vectormatches;
    fbMatcher.match(descriptor_obj, descriptor_scene, matches);


    //绘制匹配线
    Mat resultImg;
    drawMatches(img1, keypoints_obj, img2, keypoints_scene, matches, resultImg,
        Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

    /*最后一个参数使用DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS就可以把检测到的特征点隐去,
    只留下匹配到的特征点。*/

    imshow("AKAZE Matches", resultImg);

    /*那么上面的操作所显示的结果匹配到的特征点很多,为了减少多余的特征点,下面进行
    如下操作*/

    vectorgoodmatches;//保存从众多匹配点中找出的最优点
    /*
    1、遍历整个描述子;
    2、从描述子中找出最优匹配点(距离最小)
    */
    double minDist = 1000;//初始化
    double maxDist = 0;
    for (int i = 0; i < descriptor_obj.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist > maxDist)
        {
            maxDist = dist;
        }
        if (dist < minDist)
        {
            minDist = dist;
        }

    }
    for (int i = 0; i < descriptor_obj.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist < max(2 * minDist, 0.02))
        {
            goodmatches.push_back(matches[i]);
        }

    }
    Mat goodmatchesImg;
    drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodmatches, goodmatchesImg,
        Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    imshow("goodmatchesImg", goodmatchesImg);


    //用线匹配不直观,用透视矩阵来做
      //-------------------平面对象识别(将匹配到的内容替换为矩形)--------------------------
      //生成透视变换矩阵
    vector obj;
    vector objinscene;

    for (size_t i = 0; i < goodmatches.size(); i++)
    {
        obj.push_back(keypoints_obj[goodmatches[i].queryIdx].pt);
        objinscene.push_back(keypoints_scene[goodmatches[i].trainIdx].pt);
    }
    Mat H = findHomography(obj, objinscene, RANSAC);     //生成透视变换矩阵

    vector obj_corner(4);//源图片4个角的坐标
    vector objinscene_corner(4);
    obj_corner[0] = Point(0, 0);
    obj_corner[1] = Point(img1.cols, 0);
    obj_corner[2] = Point(img1.cols, img1.rows);
    obj_corner[3] = Point(0, img1.rows);


    //------------------透视变换---------------------
    perspectiveTransform(obj_corner, objinscene_corner, H);
    Mat pptfImg = goodmatchesImg.clone();
    line(pptfImg, objinscene_corner[0] + Point2f(img1.cols, 0), objinscene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, objinscene_corner[1] + Point2f(img1.cols, 0), objinscene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, objinscene_corner[2] + Point2f(img1.cols, 0), objinscene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, objinscene_corner[3] + Point2f(img1.cols, 0), objinscene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);

    imshow("pptfImg", pptfImg);

    waitKey(0);
    return 0;
}


P60 Brisk特征检测与匹配*****成功啦

#include
#include
#include

using namespace cv;
using namespace std;


int main(int argc, char**argv)
{
    Mat img1 = imread("C:/Users/25503/Desktop/888.png", IMREAD_GRAYSCALE);
    Mat img2 = imread("C:/Users/25503/Desktop/999.png", IMREAD_GRAYSCALE);
    if (!img1.data || !img2.data)
    {
        cout << "图片未找到!!!" << endl;
        return -1;
    }
    imshow("img1_box", img1);
    imshow("img2_scene", img2);
    //用Brisk算法去检测特征点
    vector keypoint_obj;
    vector keypoint_scene;
    double t1 = getTickCount();//计算运行时间

    Ptr detect = BRISK::create();
    Mat desciptor_obj, descriptor_scene;
    //检测并计算描述子
    detect->detectAndCompute(img1, Mat(), keypoint_obj, desciptor_obj);
    detect->detectAndCompute(img2, Mat(), keypoint_scene, descriptor_scene);

    double t2 = getTickCount();
    double t = (t2 - t1) * 1000 / getTickFrequency();
    //匹配描述子,这里使用FLANN匹配,也可以使用(BF)暴力匹配
    vector matches;
    FlannBasedMatcher fbmatcher(new flann::LshIndexParams(20, 10, 2));
    //匹配描述子
    fbmatcher.match(desciptor_obj, descriptor_scene, matches);
    vector goodmatches;//找到最优匹配点
    double minDist = 1000;
    double maxDist = 0;//初始化

    for (int i = 0; i < desciptor_obj.rows; i++)
    {
        double dist = matches[i].distance;
        if (dist > maxDist)
        {
            maxDist = dist;
        }
        if (dist < minDist)
        {
            minDist = dist;
        }


    }
    for (int i = 0; i < desciptor_obj.rows; i++)
    {
        double dist = matches[i].distance;
        //比最小距离还小的就是最优匹配点
        if (dist < max(2 * minDist, 0.02))
        {
            goodmatches.push_back(matches[i]);

        }
    }
    Mat resultImg;
    drawMatches(img1, keypoint_obj, img2, keypoint_scene, goodmatches, resultImg,
        Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    imshow("BRISK Matches demo", resultImg);
    printf("BRISK 执行时间为(ms):%f", t);

    //使用透视矩阵画出匹配物体
    vector obj;
    vector scene_in_obj;

    for (size_t i = 0; i < goodmatches.size(); i++)
    {
        obj.push_back(keypoint_obj[goodmatches[i].queryIdx].pt);
        scene_in_obj.push_back(keypoint_scene[goodmatches[i].trainIdx].pt);

    }
    //生成透视矩阵
    Mat H = findHomography(obj, scene_in_obj, RANSAC);

    vectorobj_corner(4);
    vectorscene_corner(4);
    obj_corner[0] = Point(0, 0);
    obj_corner[1] = Point(img1.cols, 0);
    obj_corner[2] = Point(img1.cols, img1.rows);
    obj_corner[3] = Point(0, img1.rows);

    //透视变换
    perspectiveTransform(obj_corner, scene_corner, H);
    Mat pptfImg = resultImg.clone();
    line(pptfImg, scene_corner[0] + Point2f(img1.cols, 0), scene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, scene_corner[1] + Point2f(img1.cols, 0), scene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, scene_corner[2] + Point2f(img1.cols, 0), scene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    line(pptfImg, scene_corner[3] + Point2f(img1.cols, 0), scene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
    imshow("pptfImg demo", pptfImg);

    waitKey(0);
    return 0;

}

P61 级联分类器--人脸识别**********************成功

#include
#include
#include

using namespace cv;
using namespace std;


int main(int argc, char**argv)
{
    String cascadeFilePath = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";//也可以选择其他,例如眼睛等
    CascadeClassifier face_casade;
    if (!face_casade.load(cascadeFilePath))
    {
        printf("could not load haar data...\n");
        return -1;
    }

    Mat  src, gray_src;
    src = imread("C:/Users/25503/Desktop/324.jpg");
    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    equalizeHist(gray_src, gray_src);

    vector faces;
    face_casade.detectMultiScale(gray_src, faces, 1.1, 2, 0, Size(120, 120));//size(x,y)的大小可以调节,数值越大,则目标越少
    for (size_t t = 0; t < faces.size(); t++)
    {
        rectangle(src, faces[t], Scalar(0, 0, 255), 3, 8, 0);//绘制矩形框,线宽,线性,线颜色

    }
    namedWindow("output", CV_WINDOW_AUTOSIZE);
    imshow("output", src);


    waitKey(0);
    return 0;

}

P62概述(无代码)

P63-P65 案例一 切边01 法律文件切边

#include
#include
#include

using namespace cv;
using namespace std;

Mat src, dst, gray_src;

int current_level = 50;
int max_level = 255;
void cut_image(int, void*);

const char* output_title = "rectminArea";
int main(int argc, char**argv)
{
    src = imread("C:/Users/25503/Desktop/6667.png", 1);
    if (src.empty())
    {
        cout << "图片未找到" << endl;
        return -1;
    }


    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    createTrackbar("Value", output_title, ¤t_level, max_level, cut_image);
    cut_image(0, 0);
    imshow("input image", src);
    waitKey(0);
    return 0;

}
void cut_image(int, void*)
{
    Mat canyImg;
    cvtColor(src, gray_src, CV_BGR2GRAY);
    Canny(gray_src, canyImg, current_level, 2 * current_level, 3, false);

    vector> contours;
    vectorhierachy;
    Mat showImg = Mat::zeros(src.size(), CV_8UC3);
    findContours(canyImg, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    RNG rng(12345);

    int minw = src.cols*0.75;
    int minh = src.rows*0.75;

    Rect box; //获取roi区域
    Mat contoursimg = Mat::zeros(src.size(), CV_8UC3);
    for (size_t t = 0; t < contours.size(); t++)
    {
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));

        drawContours(contoursimg, contours, int(t), color, 1, 8, hierachy, 0, Point(0, 0));

        RotatedRect minrect = minAreaRect(contours[t]); //获取轮廓的最小外接矩形
        float angle = abs(minrect.angle);
        if (minrect.size.height > minh && minrect.size.width > minw && minrect.size.width < (src.cols - 5))
        {
            Point2f pts[4];
            minrect.points(pts); //获取最小外接矩形的四个顶点坐标
            for (int i = 0; i < 4; i++)
            {
                line(showImg, pts[i], pts[(i + 1) % 4], color, 2, 8, 0);
                cout << "X坐标:" << minrect.center.x << " " << "Y坐标:" << minrect.center.y << " " << "偏移角度:" << angle << endl;
            }
            box = minrect.boundingRect();
        }

        if (box.width > 0 && box.height > 0)
        {
            Mat roiImg = src(box);//截取roi区域
            imshow("roiImg", roiImg);
        }

    }

    imshow(output_title, showImg);
    imshow("contours image", contoursimg);


}


P66 -P67 案例二 直线检测

#include
#include
#include

using namespace cv;
using namespace std;

void houghlinedetect(int, void*);  //定义霍夫检测直线的方法
void morphlogy_houghline(int, void*);//定义形态学+霍夫直线变换的方法

Mat src, roiImg, dst, gray_dst;
int threshold_value = 50;
int max_value = 255;
const char* output_title = "detect lines";

int main(int argc, char** argv)
{
    src = imread("C:/Users/25503/Desktop/668.png", 1);
    if (src.empty())
    {
        cout << "图片未找到!" << endl;
        return -1;
    }

    imshow("input image", src);
    Rect roi = Rect(8, 8, src.cols - 10, src.rows - 10); //从左上角(8,8),选取这块ROI区域
    roiImg = src(roi);

    namedWindow(output_title, CV_WINDOW_AUTOSIZE);
    //createTrackbar("threshold", output_title, &threshold_value, max_value, houghlinedetect);
    //houghlinedetect(0, 0);
    morphlogy_houghline(0, 0);
    imshow("roiImg", roiImg);
    waitKey(0);
    return 0;
}

void houghlinedetect(int, void *)
{
    //使用边缘检测将图片二值化
    Canny(roiImg, dst, threshold_value, 2 * threshold_value, 3, false);

    //bitwise_not(dst, dst, Mat());
    vector lines;//存储直线数据
    HoughLinesP(dst, lines, 1, CV_PI / 180.0, 30, 30, 0); //源图需要是二值图像,HoughLines也是一样

    cvtColor(dst, gray_dst, COLOR_GRAY2BGR); //GRAY2BGR也是转化为灰度图像的,霍夫变换-直线检测需要使用这个,BGR2GRAY会报错。
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i l = lines[i];
        line(gray_dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);

    }
    imshow(output_title, gray_dst);

}

void morphlogy_houghline(int, void*)
{

    //二值化操作
    Mat binaryImage, morhpImage, resultImg, dilateImg;
    cvtColor(roiImg, roiImg, CV_BGR2GRAY);
    threshold(roiImg, binaryImage, 0, 255, THRESH_BINARY | THRESH_OTSU);//THRESH_BINARY|THRESH_OTSU 自动确定阈值
    bitwise_not(binaryImage, binaryImage, Mat());//当然在threshold中可以使用THRESH_BINARY | THRESH_OTSU直接变成黑色背景
    imshow("binary", binaryImage);


    //形态学操作,去除除了横线以外的所有字
    Mat kernel = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));//结构元素,这里使用矩形结构元素,Size(30,1)保留横线,point(-1,-1)表示中心
    morphologyEx(binaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
    imshow("morphologyEx result", morhpImage);

    //使用膨胀操作把直线变得更明显点
    kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    dilate(morhpImage, dilateImg, kernel, Point(-1, -1));
    imshow("dilateimg result", dilateImg);

    //霍夫直线检测
    vector lines;
    resultImg = roiImg.clone();

    HoughLinesP(dilateImg, lines, 1, CV_PI / 180.0, 20, 5, 0);
    cvtColor(resultImg, resultImg, CV_GRAY2RGB);
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i L = lines[i];

        line(resultImg, Point(L[0], L[1]), Point(L[2], L[3]), Scalar(0, 0, 255), 2, 8, 0);

    }
    imshow("final result", resultImg);
}

P68-P69 对象提取--在混有噪声的地图轮廓上,将地图轮廓提取出来,并计算轮廓周长与面积

#include
#include
#include

using namespace cv;
using namespace std;

Mat src;
int main(int argc, char** argv)
{
    src = imread("C:/Users/25503/Desktop/6689.jpg");
    if (src.empty())
    {
        printf("图片未找到!!!");
        return -1;
    }
    imshow("inut image", src);
    //高斯模糊
    Mat GaussImg;
    GaussianBlur(src, GaussImg, Size(7, 7), 0, 0);
    imshow("Gauss Image", GaussImg);
    cvtColor(GaussImg, GaussImg, CV_BGR2GRAY);

    //二值化操作
    Mat binary;
    threshold(GaussImg, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
    imshow("binary Image", binary);

    //形态学操作
    Mat morphImg;
    Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
    morphologyEx(binary, morphImg, MORPH_CLOSE, kernel, Point(-1, -1), 1);
    imshow("morph Image", morphImg);

    //轮廓发现
    Mat contoursImg = Mat::zeros(src.size(), CV_8UC3);
    vector>contours;
    vectorhireachy;
    findContours(morphImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(-1, -1));

    for (size_t i = 0; i < contours.size(); i++)
    {
        Rect rect = boundingRect(contours[i]);
        if (rect.width < src.cols / 2)
            continue;

        drawContours(contoursImg, contours, static_cast(i),
            Scalar(0, 0, 255), 2, 8, hireachy, 0, Point(0, 0));
        //计算面积与周长
        float area = contourArea(contours[i]);
        float length = arcLength(contours[i], true);
        printf("对象图像面积为:%f\n", area);
        printf("对象图像周长为:%f\n", length);

    }
    imshow("contours Image", contoursImg);

    waitKey(0);
    return 0;

}


P70-P71 图像计数-----计算玉米粒个数

#include
#include
#include

using namespace cv;
using namespace std;


int main(int argc, char** argv)
{
    Mat src = imread("C:/Users/25503/Desktop/1010.jpg");
    //medianBlur(src, src,5);//中值滤波,去除椒盐噪声
    imshow("src", src);

    Mat src_gray, binary;

    cvtColor(src, src_gray, COLOR_BGR2GRAY);

    threshold(src_gray, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);//颜色单一时,使用THRESH_TRIANGLE比OTSU好
    imshow("binary", binary);

    //形态学操作
    Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
    dilate(binary, binary, kernel, Point(-1, -1), 4);

    //距离变换
    Mat dist;
    bitwise_not(binary, binary);//取反
    distanceTransform(binary, dist, CV_DIST_L2, 3);
    normalize(dist, dist, 0, 1.0, NORM_MINMAX);
    imshow("dist", dist);

    //阈值化二值分割
    //threshold(dist, dist,0.7,1.0,THRESH_BINARY);//对距离进行筛选,去除边缘部分
    //normalize(dist, dist, 0, 255, NORM_MINMAX);
    Mat dist_8U;
    dist.convertTo(dist_8U, CV_8U);
    adaptiveThreshold(dist_8U, dist_8U, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 85, 0.0);//自适应阈值,代替上面的阈值操作
    //形态学操作,使得断开部分连接
    kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
    dilate(dist_8U, dist_8U, kernel, Point(-1, -1), 3);

    imshow("dist_8U", dist_8U);

    // 连通区域计数
    vector> contours;
    findContours(dist_8U, contours, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // draw result
    Mat markers = Mat::zeros(src.size(), CV_8UC3);
    RNG rng(12345);
    for (size_t t = 0; t < contours.size(); t++) {
        drawContours(markers, contours, static_cast(t), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)),
            -1, 8, Mat());
    }
    printf("number of corns : %d", contours.size());
    imshow("Final result", markers);

    waitKey(0);

    return 0;
}

P72-P75 透视校正:拍摄/扫描出来的图片倾斜,校正成正向图形********

# include
# include
# include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/522.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return 0;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    //二值处理
    Mat gray_src, binary, dst;
    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    threshold(gray_src, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);//可以将THRESH_BINARY转化为THRESH_BINARY_INV
    imshow("binary image", binary);

    //形态学操作
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    morphologyEx(binary, dst, MORPH_CLOSE, kernel, Point(-1, -1), 3);
    imshow("morphology", dst);
    
    //轮廓发现
    bitwise_not(dst, dst, Mat());
    vector> contours;
    vector hireachy;
    findContours(dst, contours, hireachy, CV_RETR_TREE, CHAIN_APPROX_SIMPLE, Point());

    //轮廓绘制
    int width = src.cols;
    int height = src.rows;
    Mat drawImage = Mat::zeros(src.size(), CV_8UC3);
    for (size_t t = 0; t < contours.size(); t++)
    {
        Rect rect = boundingRect(contours[t]);
        if (rect.width > width / 2 && rect.width < width - 5)
        {
            drawContours(drawImage, contours, static_cast(t), Scalar(0, 0, 255), 2, 8, hireachy, 0, Point());

        }
    }
    imshow("contours", drawImage);

    vector lines;
    Mat contourImg;
    int accu = min(width*0.5, height*0.5);
    cvtColor(drawImage, contourImg, COLOR_BGR2GRAY);
    HoughLinesP(contourImg, lines, 1, CV_PI / 180.0, accu, accu, 0);
    Mat linesImage = Mat::zeros(src.size(), CV_8UC3);
    for (size_t t = 0; t < lines.size(); t++)
    {
        Vec4i In = lines[t];
        line(linesImage, Point(In[0], In[1]), Point(In[2], In[3]), Scalar(0, 0, 255), 2, 8, 0);
    }
    printf("number of lines :%d", lines.size());
    imshow("lines image", linesImage);

    //寻找与定位上下左右四条直线
    int deltah = 0;
    Vec4i topLine, bottomLine;
    Vec4i leftLine, rightLine;
    for (int i = 0; i < lines.size(); i++)
    {
        Vec4i In = lines[i];
        deltah = abs(In[3] - In[1]);
        if (In[3] < height / 2.0 && In[1] < height / 2.0 && deltah < accu - 1)
        {
            topLine = lines[i];
        }
        if (In[3] > height / 2.0 && In[1] > height / 2.0 && deltah < accu - 1)
        {
            bottomLine = lines[i];
        }
        if (In[0] < width / 2.0 && In[2]         {
            leftLine = lines[i];
        }
        if (In[0] > width / 2.0 && In[2] > width / 2.0)
        {
            rightLine = lines[i];
        }
    }
    cout << "top line:p1(x,y) =" << topLine[0] << "," << topLine[1] << "p2(x,y) =" << topLine[2] << "," << topLine[3] << endl;
    cout << "bottom line:p1(x,y) =" << bottomLine[0] << "," << bottomLine[1] << "p2(x,y) =" << bottomLine[2] << "," << bottomLine[3] << endl;
    cout << "left line:p1(x,y) =" << leftLine[0] << "," << leftLine[1] << "p2(x,y) =" << leftLine[2] << "," << leftLine[3] << endl;
    cout << "right line:p1(x,y) =" << rightLine[0] << "," << rightLine[1] << "p2(x,y) =" << rightLine[2] << "," << rightLine[3] << endl;

    //拟合四条直线方程
    float k1, c1;
    k1 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
    c1 = topLine[1] - k1 * topLine[0];

    float k2, c2;
    k2 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
    c2 = topLine[1] - k2 * topLine[0];

    float k3, c3;
    k3 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
    c3 = topLine[1] - k3 * topLine[0];

    float k4, c4;
    k4 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
    c4 = topLine[1] - k4 * topLine[0];

    //四条直线交点
    Point p1;//左上角点
    p1.x = static_cast((c1 - c3) / (k3 - k1));
    p1.y = static_cast (k3*p1.x + c3);

    Point p2;//右上角点
    p2.x = static_cast((c1 - c4) / (k4 - k1));
    p2.y = static_cast (k1*p2.x + c1);

    Point p3;//左下角点
    p3.x = static_cast((c2 - c3) / (k3 - k2));
    p3.y = static_cast (k3*p3.x + c3);

    Point p4;//右下角点
    p4.x = static_cast((c2 - c4) / (k4 - k2));
    p4.y = static_cast (k4*p4.x + c4);

    cout << "p1(x,y) =" << p1.x << "," << p1.y << endl;
    cout << "p2(x,y) =" << p2.x << "," << p2.y << endl;
    cout << "p3(x,y) =" << p3.x << "," << p3.y << endl;
    cout << "p4(x,y) =" << p4.x << "," << p4.y << endl;

    //显示四个点坐标
    circle(linesImage, p1, 2, Scalar(255, 0, 0), 2, 8, 0);
    circle(linesImage, p2, 2, Scalar(255, 0, 0), 2, 8, 0);
    circle(linesImage, p3, 2, Scalar(255, 0, 0), 2, 8, 0);
    circle(linesImage, p4, 2, Scalar(255, 0, 0), 2, 8, 0);
    line(linesImage, Point(topLine[0], topLine[1]), Point(topLine[2], topLine[3]), Scalar(0, 255, 0), 2, 8, 0);
    imshow("four corners", linesImage);

    //透视变换
    vector src_corners(4);
    src_corners[0] = p1;
    src_corners[1] = p2;
    src_corners[2] = p3;
    src_corners[3] = p4;

    vector dst_corners(4);
    dst_corners[0] = Point(0, 0);
    dst_corners[1] = Point(width, 0);
    dst_corners[2] = Point(0, height);
    dst_corners[3] = Point(width,height);

    //获取透视变换矩阵warpmatrix
    Mat resultImage;
    Mat warpmatrix = getPerspectiveTransform(src_corners, dst_corners);
    warpPerspective(src, resultImage, warpmatrix, resultImage.size(), INTER_LINEAR);
    namedWindow("Final Result", CV_WINDOW_AUTOSIZE);
    imshow("Final Result", resultImage);

    waitKey(0);
    return 0;
}


P76 对象提取与测量(代码与P68-P69相同)

P77级联分类器训练与使用实战概述

P78 Haar与LBP级联分类器(例如,人脸识别、分苹果案例)********************(基于图片)成功

# include
# include

using namespace cv;
using namespace std;

String fileName = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";//人脸库,也可以加上眼睛
CascadeClassifier face_classifier;

int main(int agrc, char** agrv)
{
    if (!face_classifier.load(fileName))
    {
        printf("could not load face feature data...\n");
        return -1;
    }
    Mat src = imread("C:/Users/25503/Desktop/327.jpg");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    equalizeHist(gray, gray);

    vector faces;
    face_classifier.detectMultiScale(gray, faces, 1.2, 3, 0, Size(24, 24));
    for (size_t t = 0; t < faces.size(); t++)
    {
        rectangle(src, faces[static_cast(t)], Scalar(0, 0, 255), 2, 8, 0);
    }
    namedWindow("detect faces", CV_WINDOW_AUTOSIZE);
    imshow("detect faces", src);

    waitKey(0);
    return 0;
}


P79 Haar与LBP级联分类器(人脸识别)************(基于摄像头)
P79-(1)基于摄像头识别人脸***********成功
# include
# include

using namespace cv;
using namespace std;

CascadeClassifier face_cascader;
String filename = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";
int main(int agrc, char** agrv)
{
    if (!face_cascader.load(filename))
    {
        printf("could not load face feature data...\n");
        return -1;
    }
    namedWindow("camera-demo", CV_WINDOW_AUTOSIZE);
    VideoCapture capture(0);
    Mat frame;
    Mat gray;
    vector faces;
    while (capture.read(frame))
    {
        cvtColor(frame, gray, COLOR_BGR2GRAY);
        equalizeHist(gray, gray);
        face_cascader.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
        for (size_t t = 0; t < faces.size(); t++)
        {
            rectangle(frame, faces[static_cast(t)], Scalar(0, 0, 255), 2, 8, 0);

        }
        imshow("camera-demo", frame);
        char c = waitKey(30);
        if (c == 27)
        {
            break;
        }
    }


    waitKey(0);
    return 0;
}

P79-(2)基于摄像头识别人脸+人眼睛************成功

# include
# include

using namespace cv;
using namespace std;

CascadeClassifier face_cascader;
CascadeClassifier eye_cascader;

String facefile = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";
String eyefile = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_eye.xml";

int main(int agrc, char** agrv)
{
    if (!face_cascader.load(facefile))
    {
        printf("could not load face feature data...\n");
        return -1;
    }
    if (!eye_cascader.load(eyefile))
    {
        printf("could not load face feature data...\n");
        return -1;
    }
    namedWindow("camera-demo", CV_WINDOW_AUTOSIZE);
    VideoCapture capture(0);
    Mat frame;
    Mat gray;
    vector faces;
    vector eyes;
    while (capture.read(frame))
    {
        cvtColor(frame, gray, COLOR_BGR2GRAY);
        equalizeHist(gray, gray);

        face_cascader.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
        for (size_t t = 0; t < faces.size(); t++)
        {
            Rect roi;//定位在脸部范围
            roi.x = faces[static_cast(t)].x;
            roi.y = faces[static_cast(t)].y;
            roi.width = faces[static_cast(t)].width;
            roi.height = faces[static_cast(t)].height;

            Mat faceROI = frame(roi);
            eye_cascader.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(20, 20));
            for (size_t k = 0; k < eyes.size(); k++)
            {
                Rect rect;
                rect.x = faces[static_cast(t)].x + eyes[k].x;
                rect.y = faces[static_cast(t)].y + eyes[k].y;
                rect.width = eyes[k].width;
                rect.height = eyes[k].height;
                rectangle(frame, rect, Scalar(0, 255, 255), 2, 8, 0);
            }
            rectangle(frame, faces[static_cast(t)], Scalar(0, 0, 255), 2, 8, 0);

        }
        imshow("camera-demo", frame);
        char c = waitKey(30);
        if (c == 27)
        {
            break;
        }
    }


    waitKey(0);
    return 0;
}

P79-(3) 基于摄像头识别人脸+嘴部(博士任务)

P80 图像分割概述

P81-P83 Kmeans方法-原理、数据聚类、图像分割

(1) Kmeans数据分类程序代码:

# include
# include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat img(500, 500, CV_8UC3);
    RNG rng(12345);

    Scalar colorTab[] = {
        Scalar(0,0,255),
        Scalar(0,255,0),
        Scalar(255,0,0),
        Scalar(0,255,255),
        Scalar(255,0,255)
    };

    int numCluster = rng.uniform(2, 5);
    printf("number of clusters:%d\n", numCluster);

    int sampleCount = rng.uniform(5, 1000);
    Mat points(sampleCount, 1, CV_32FC2);
    Mat labels;
    Mat centers;

    //生成随机数
    for (int k = 0; k < numCluster; k++)
    {
        Point center;
        center.x = rng.uniform(0, img.cols);
        center.y = rng.uniform(0, img.rows);
        Mat pointChunk = points.rowRange(k*sampleCount / numCluster, k == numCluster - 1 ? sampleCount:(k + 1)*sampleCount / numCluster);
        rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));


    }
    randShuffle(points, 1, &rng);

    //使用KMeans
    kmeans(points, numCluster, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);

    //用不同颜色显示分类
    img = Scalar::all(255);
    for (int i = 0; i < sampleCount; i++)
    {
        int index = labels.at(i);
        Point p = points.at(i);
        circle(img, p, 2, colorTab[index], -1, 8);

    }

    //每个聚类的中心来绘制圆
    for (int i = 0; i < centers.rows; i++)
    {
        int x = centers.at(i, 0);
        int y = centers.at(i, 1);
        printf("c.x =%d, c.y =%d", x, y);
        circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA);
    }
    imshow("KMeans-Data-Demo", img);

    waitKey(0);
    return 0;
}


(2) Kmens对图像进行分割程序代码:******

# include
# include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/888.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    Scalar colorTab[] =
    {
        Scalar(0,0,255),
        Scalar(0,255,0),
        Scalar(255,0,0),
        Scalar(0,255,255),
        Scalar(255,0,255)
    };

    int width = src.cols;
    int height = src.rows;
    int dims = src.channels();

    //初始化定义
    int sampleCount = width * height;
    int clusterCount = 4;
    Mat points(sampleCount, dims, CV_32F, Scalar(10));
    Mat labels;
    Mat centers(clusterCount, 1, points.type());

    //RGB数据转换到样本数据
    int index = 0;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            Vec3b bgr = src.at(row, col);
            points.at(index, 0) = static_cast(bgr[0]);
            points.at(index, 1) = static_cast(bgr[1]);
            points.at(index, 2) = static_cast(bgr[2]);
        }
    }
    //运行K-Means
    TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
    kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);

    //显示图像分割结果
    Mat result = Mat::zeros(src.size(), src.type());
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            int label = labels.at(index, 0);
            result.at(row, col)[0] = colorTab[label][0];
            result.at(row, col)[1] = colorTab[label][1];
            result.at(row, col)[2] = colorTab[label][2];
        }
    }
    
    /*//每个聚类的中心来绘制圆
    for (int i = 0; i < centers.rows; i++)
    {
        int x = centers.at(i, 0);
        int y = centers.at(i, 1);
        printf("c.x =%d, c.y =%d", x, y);
        circle(result, Point(x, y), 40, colorTab[i], 1, LINE_AA);
    }
    */

    imshow("KMeans image Segmentation Demo", result);
    waitKey(0);
    return 0;
}

P84 高斯混合模型(GMM)方法原理:


P85 高斯混合模型(GMM)进行图像分割处理:

#include
#include

using namespace std;
using namespace cv;
int main()
{
    Mat srcImg = imread("C:/Users/25503/Desktop/888.png");
    imshow("srcImg", srcImg);

    Scalar colorsTab[] = {
        Scalar(255, 0, 0),
        Scalar(0, 255, 0),
        Scalar(0, 0, 255),
        Scalar(255, 255, 0)
    };
    int width = srcImg.cols;
    int height = srcImg.rows;
    int dims = srcImg.channels();
    int numCluster = 4;
    int numSample = width * height;

    Mat points(numSample, dims, CV_64FC1);//在EM中数据是64位的
    Mat labels;

    // 图像RGB像素数据转换为样本数据 
    int index = 0;
    for (int row = 0; row < height; row++) // 这里的步骤与KMeans是一样的
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            Vec3b bgr = srcImg.at(row, col);
            points.at(index, 0) = static_cast(bgr[0]);
            points.at(index, 1) = static_cast(bgr[1]);
            points.at(index, 2) = static_cast(bgr[2]);
        }
    }

    double time0 = getTickCount();
    //EM Cluster Train
    Ptr em_model = ml::EM::create(); // 生成 EM 期望最大化,其图像分割的方式是基于机器学习的方式
    em_model->setClustersNumber(numCluster); // 设置分类数
    em_model->setCovarianceMatrixType(ml::EM::COV_MAT_SPHERICAL); // 协方差矩阵类型
    em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1)); // 迭代条件,EM训练比KMeans耗时,可能会不收敛,所以迭代次数设大点
    em_model->trainEM(points, noArray(), labels, noArray()); // EM训练,获得分类结果,参数labels与KMeans的labels参数意思一样,速度比KMeans要慢很多
    cout << "train time=" << (getTickCount() - time0) / getTickFrequency() << endl; // train time=10425.8  训练所需的时间很长

    // 对每个像素标记颜色与显示
    Mat result_nopredict = Mat::zeros(srcImg.size(), CV_8UC3);
    Mat result_predict = Mat::zeros(srcImg.size(), CV_8UC3);
    Mat sample(dims, 1, CV_64FC1); // 也只能用 CV_64F
    time0 = getTickCount();
    int r = 0, g = 0, b = 0;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            // 获取训练的分类结果,放到 result_nopredict 中
            index = row * width + col;
            int label = labels.at(index, 0);
            Scalar c = colorsTab[label];
            result_nopredict.at(row, col)[0] = c[0];
            result_nopredict.at(row, col)[1] = c[1];
            result_nopredict.at(row, col)[2] = c[2];

            // 通过预言获得分类结果,因为EM训练用的是src的颜色数据,所以用src的颜色数据做预言,得到的结果与 result_nopredict 是一模一样的
            b = srcImg.at(row, col)[0];
            g = srcImg.at(row, col)[1];
            r = srcImg.at(row, col)[2];
            sample.at(0) = b;
            sample.at(1) = g;
            sample.at(2) = r;
            Vec2d predict = em_model->predict2(sample, noArray());  // 预言,预言的时间是很短的
            int response = cvRound(predict[1]);                        // response 就是目标颜色数据在EM训练中预言的分类
            c = colorsTab[response];
            result_predict.at(row, col)[0] = c[0];
            result_predict.at(row, col)[1] = c[1];
            result_predict.at(row, col)[2] = c[2];

        }
    }
    printf("execution time(ms) : %.2f\n", (getTickCount() - time0) / getTickFrequency()); // execution time(ms) : 1600.31
    imshow("EM-Segmentation nopredict", result_nopredict); // 从效果看,KMeans更好些
    imshow("EM-Segmentation predict", result_predict);
    waitKey(0);
    return 0;
}


P86-P89 分水岭分割原理、分离、计数
分水岭分割(硬币)程序代码:

# include
# include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/7778.png");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    //中间填充
    Mat gray, binary, shifted;
    pyrMeanShiftFiltering(src, shifted, 21, 51);
    imshow("shifted", shifted);
    
    //二值化处理
    cvtColor(shifted, gray, COLOR_BGR2GRAY);
    threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    imshow("binary", binary);

    //distance transform
    Mat dist;
    distanceTransform(binary, dist, DistanceTypes::DIST_L2, 3, CV_32F);
    normalize(dist, dist, 0, 1, NORM_MINMAX);
    imshow("distance transform result", dist);

    //binary
    threshold(dist, dist, 0.4, 1, THRESH_BINARY);
    imshow("distance binary", dist);

    //markers
    Mat dist_m;
    dist.convertTo(dist_m, CV_8U);
    vector>contours;
    findContours(dist_m, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

    //create markers
    Mat markers = Mat::zeros(src.size(), CV_32SC1);
    for (size_t t = 0; t < contours.size(); t++)
    {
        drawContours(markers, contours, static_cast(t), Scalar::all(static_cast(t) + 1), -1);

    }
    circle(markers, Point(5, 5), 3, Scalar(255), -1);
    imshow("markers", markers * 100000);


    //形态学操作-彩色图像,目的是去掉干扰,让结果更好
    Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    morphologyEx(src, src, MORPH_ERODE, k);

    //完成分水岭变换
    watershed(src, markers);
    Mat mark = Mat::zeros(markers.size(), CV_8UC1);
    markers.convertTo(mark, CV_8UC1);
    bitwise_not(mark, mark, Mat());
    imshow("watershed result",mark);


    //generate random color
    vector colors;
    for (size_t i = 0; i < contours.size();i++)
    {
        int r = theRNG().uniform(0, 255);
        int g = theRNG().uniform(0, 255);
        int b = theRNG().uniform(0, 255);
        colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
    }


    //颜色填充与最终显示
    Mat dst = Mat::zeros(markers.size(), CV_8UC3);
    int index = 0;
    for (int row = 0; row < markers.rows; row++)
    {
        for (int col = 0; col < markers.cols; col++)
        {
            index = markers.at(row, col);
            if (index > 0 && index <= contours.size())
            {
                dst.at(row, col) = colors[index - 1];
            }
            else
            {
                dst.at(row, col) = Vec3b(0,0,0);
            }
        }
    }

    imshow("Final Result", dst);
    printf("number of objects:\n %d", contours.size());


    waitKey(0);
    return 0;
}

P90 -P91 Grabcut原理与演示应用---框选图像分割内容->抠图

//鼠标选定方框后,按下键盘n键,然后按下enter键,便可进行分割。
#include
#include
#include

using namespace cv;
using namespace std;

int numRun = 0;
Rect rect;
bool init = false;
Mat src, image;
Mat mask, bgModel, fgModel;//mask,背景,前景
const char* winTitle = "input image";

void onMouse(int event, int x, int y, int flags, void* param);
void setROIMask();
void showImage();
void runGrabCut();
int main(int argc, char** argv) {
    src = imread("C:/Users/25503/Desktop/7778.png", 1);
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    mask.create(src.size(), CV_8UC1);
    mask.setTo(Scalar::all(GC_BGD));

    namedWindow(winTitle, CV_WINDOW_AUTOSIZE);//
    setMouseCallback(winTitle, onMouse, 0);//设置鼠标反馈事件
    imshow(winTitle, src);

    while (true) {
        char c = (char)waitKey(0);
        if (c == 'n') {
            runGrabCut();//运行GrabCut算法
            numRun++;
            showImage();
            printf("current iteative times : %d\n", numRun);//当前迭代次数
        }
        if ((int)c == 27) {
            break;
        }
    }

    waitKey(0);
    return 0;
}

void showImage() {
    Mat result, binMask;
    binMask.create(mask.size(), CV_8UC1);
    binMask = mask & 1;
    if (init) {
        src.copyTo(result, binMask);
    }
    else {
        src.copyTo(result);//将src图像拷贝到result中
    }
    imwrite("tx2.png", result);
    rectangle(result, rect, Scalar(0, 0, 255), 2, 8);//在result上绘制红色矩形框rect
    imshow(winTitle, result);
}

void setROIMask() {
    // GC_FGD = 1
    // GC_BGD =0;
    // GC_PR_FGD = 3
    // GC_PR_BGD = 2
    mask.setTo(GC_BGD);
    rect.x = max(0, rect.x);
    rect.y = max(0, rect.y);
    rect.width = min(rect.width, src.cols - rect.x);
    rect.height = min(rect.height, src.rows - rect.y);
    mask(rect).setTo(Scalar(GC_PR_FGD));
}

//鼠标事件函数
void onMouse(int event, int x, int y, int flags, void* param) {
    switch (event)
    {
    case EVENT_LBUTTONDOWN://鼠标左键按下
        rect.x = x;//矩形左上角x,y坐标
        rect.y = y;
        rect.width = 1;//矩形线条宽度、高度
        rect.height = 1;
        init = false;
        numRun = 0;
        break;
    case EVENT_MOUSEMOVE://鼠标移动
        if (flags & EVENT_FLAG_LBUTTON) {
            rect = Rect(Point(rect.x, rect.y), Point(x, y));
            showImage();//显示带矩形框的图像
        }
        break;
    case EVENT_LBUTTONUP://鼠标左键松开
        if (rect.width > 1 && rect.height > 1) {
            setROIMask();
            showImage();
        }
        break;
    default:
        break;
    }
}

//运行GrabCut函数
void runGrabCut() {
    if (rect.width < 2 || rect.height < 2) {
        return;
    }

    if (init) {
        grabCut(src, mask, rect, bgModel, fgModel, 1);
    } {
        grabCut(src, mask, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);
        init = true;
    }
}

P92-P93 证件照背景替换*******


#include
#include

using namespace std;
using namespace cv;

void ChangeImgBG();
Mat HandleImgData(Mat& img);
/*
图片背景替换
知识点:分水岭分割、高斯模糊
处理步骤:数据组装-KMeans分割-背景消除-生成遮罩-模糊-输出
*/
void ChangeImgBG()
{
    const char* win1 = "原图";
    const char* win2 = "腐蚀图";
    const char* win3 = "高斯模糊图";
    const char* win4 = "换底图";
    //WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
    //WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小.
    namedWindow(win1, WINDOW_NORMAL);//创建窗口 win1
    namedWindow(win2, WINDOW_NORMAL);//创建窗口 win2
    namedWindow(win3, WINDOW_NORMAL);//创建窗口 win3
    namedWindow(win4, WINDOW_NORMAL);//创建窗口 win4

    Mat img1, img2, img3;
    //加载图片
    img1 = imread("C:/Users/25503/Desktop/樊玉和.jpg");//读入要处理的图片//图片放在工程目录下,与 .cpp文件同目录
    if (img1.empty())
    {
        cout << "image not found..." << endl;
        exit(0);//如果图片不存在,退出程序
    }
    img2 = img1.clone();
    //显示原始图片
    imshow(win1, img1);
    //组装数据
    Mat points = HandleImgData(img1);

    //Kmeans处理
    int numCluster = 4;
    Mat labels;
    Mat centers;
    TermCriteria termCriteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);

    kmeans(points, numCluster, labels, termCriteria, 3, KMEANS_PP_CENTERS, centers);
    //遮罩
    Mat mask = Mat::zeros(img1.size(), CV_8UC1);
    int index = img1.rows * 2 + 2;
    int cindex = labels.at(index, 0);//背景设置为0
    int height = img1.rows;
    int width = img1.cols;

    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            int label = labels.at(index, 0);
            if (label == cindex)
            {
                img2.at(row, col)[0] = 0;
                img2.at(row, col)[1] = 0;
                img2.at(row, col)[2] = 0;
                mask.at(row, col) = 0;
            }
            else
            {
                mask.at(row, col) = 255;
            }
        }
    }

    //腐蚀
    Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    erode(mask, mask, k);
    imshow(win2, mask);

    //高斯模糊
    GaussianBlur(mask, mask, Size(3, 3), 0, 0);
    imshow(win3, mask);

    //通道混合
    RNG rng(12345);


    //背景颜色调整
    Vec3b color; //RGB三原色可以任意组合 ,注意下面的数组顺序是BGR
        /*color[0] = rng.uniform(255, 255);
        color[1] = rng.uniform(255, 255);
        color[2] = rng.uniform(255, 255);*/
        color[0] = 255;  //B
    color[1] = 255;  //G
    color[2] = 255;  //R

    Mat result(img1.size(), img1.type());

    double d1 = 0.0;
    int r = 0, g = 0, b = 0;
    int r1 = 0, g1 = 0, b1 = 0;
    int r2 = 0, g2 = 0, b2 = 0;


    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            int m = mask.at(row, col);
            if (m == 255)
            {
                result.at(row, col) = img1.at(row, col);//前景
            }
            else if (m == 0)
            {
                result.at(row, col) = color;//背景
            }
            else
            {
                d1 = m / 255.0;
                b1 = img1.at(row, col)[0];
                g1 = img1.at(row, col)[1];
                r1 = img1.at(row, col)[2];

                b2 = color[0];
                g2 = color[1];
                r2 = color[2];

                b = b1 * d1 + b2 * (1.0 - d1);
                g = g1 * d1 + g2 * (1.0 - d1);
                r = r1 * d1 + r2 * (1.0 - d1);

                result.at(row, col)[0] = b;
                result.at(row, col)[1] = g;
                result.at(row, col)[2] = r;
            }
        }
    }

    //输出
    imshow(win2, mask);
    imshow(win3, img2);
    imshow(win4, result);
    //保存处理后的图片
    imwrite("result1.jpg", result);//换底后的图片以result1.jpg保存在.cpp文件目录下

}

//组装样本数据
Mat HandleImgData(Mat& img)
{
    int width = img.cols;
    int height = img.rows;
    int count1 = width * height;
    int channels1 = img.channels();

    Mat points(count1, channels1, CV_32F, Scalar(10));
    int index = 0;
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            index = row * width + col;
            Vec3b bgr = img.at(row, col);
            points.at(index, 0) = static_cast(bgr[0]);
            points.at(index, 1) = static_cast(bgr[1]);
            points.at(index, 2) = static_cast(bgr[2]);
        }
    }
    return points;
}

int main()
{
    ChangeImgBG();//换底
    waitKey(0);
    return 0;
}


P94-P95 绿色背景视频抠图


#include
#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;
const char* title = "input video";
const char* resultWin = "result voide";

Mat background_01;
Mat replace_and_blend(Mat &frame, Mat &mask);
//视频抠图
int  main(int agrc, char** grgv)
{
    background_01 = imread("C:/Users/25503/Desktop/2021.jpg");
    if (background_01.empty())
    {
        printf("could not load image ...");
        return -1;
    }

    VideoCapture capture;
    // capture.open("../image/1113.jpg")
    capture.open(0);
    if (!capture.isOpened())
    {

        printf("could not load video ...");
        return -1;
    }
    int nCount = 0;
    Mat frame, hsv, mask;
    while (capture.read(frame))
    {

        cvtColor(frame, hsv, CV_BGR2HSV);
        inRange(hsv, Scalar(35, 44, 46), Scalar(155, 255, 255), mask);
        //形态学操作
        Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
        morphologyEx(mask, mask, MORPH_CLOSE, kernel);

        erode(mask, mask, kernel);
        GaussianBlur(mask, mask, Size(3, 3), 0, 0);

        Mat result = replace_and_blend(frame, mask);

        char c = waitKey(1);
        if (c == 27)
        {
            break;
        }
        imshow("mask", mask);
        imshow("result", result);

        imshow(title, frame);

    }
    waitKey(0);
    return -1;

}

Mat replace_and_blend(Mat &frame, Mat &mask)
{

    Mat reslut = Mat::zeros(frame.size(), frame.type());
    int h = frame.rows;
    int w = frame.cols;
    int dims = frame.channels();

    //feplace and blend

    int m = 0;
    double wt = 0;
    int r = 0, g = 0, b = 0;
    int r1 = 0, g1 = 0, b1 = 0;
    int r2 = 0, g2 = 0, b2 = 0;

    for (int row = 0; row < h; row++)
    {
        uchar *current = frame.ptr(row);
        uchar *bgrow = background_01.ptr(row);
        uchar *maskrow = mask.ptr(row);
        uchar *targetrow = reslut.ptr(row);

        for (int col = 0; col < w; col++)
        {
            m = *maskrow++;
            if (m == 255)//背景
            {
                *targetrow++ = *bgrow++;
                *targetrow++ = *bgrow++;
                *targetrow++ = *bgrow++;
                current += 3;
            }
            else if (m == 0) {//前景
                *targetrow++ = *current++;
                *targetrow++ = *current++;
                *targetrow++ = *current++;
                bgrow += 3;
            }
            else {
                b1 = *bgrow++;
                g1 = *bgrow++;
                r1 = *bgrow++;

                b2 = *current++;
                g2 = *current++;
                r2 = *current++;

                //权重
                wt = m / 255.0;
                //混合
                b = b1 * wt + b2 * (1.0 - wt);
                g = g1 * wt + g2 * (1.0 - wt);
                r = r1 * wt + r2 * (1.0 - wt);

                *targetrow++ = b;
                *targetrow++ = g;
                *targetrow++ = r;
            }
        }

    }

    return  reslut;
}


P96 视频分析与对象跟踪实践(环境配置搭建)
P97-P98 视频读写

#include
#include
using namespace cv;

int main()
{
    VideoCapture capture;
    capture.open(0);
    if (!capture.isOpened())
    {
        printf("can not open ...\n");
        return -1;
    }

    Size size = Size(capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT));
    VideoWriter writer;
    writer.open("E:/image/a2.avi", CV_FOURCC('M', 'J', 'P', 'G'), 10, size, true);

    Mat frame, gray;
    namedWindow("output", CV_WINDOW_AUTOSIZE);

    while (capture.read(frame))
    {
        //转换为黑白图像
        cvtColor(frame, gray, COLOR_BGR2GRAY);
        //二值化处理 
        threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU);
        cvtColor(gray, gray, COLOR_GRAY2BGR);
        imshow("output", gray);
        writer.write(gray);
        waitKey(10);
    }

    waitKey(0);
    capture.release();
    return 0;
}


P99-P100 背景消除建模(BSM)2021/1/14


#include
#include

using namespace cv;
using namespace std;

int main(int argc, char**) {
    VideoCapture capture(0);//调用摄像头
    //capture.open("F:/video_003.avi");

    if (!capture.isOpened()) {
        printf("could not find the video file...\n");
        return -1;
    }
    // create windows
    Mat frame;
    Mat bsmaskMOG2, bsmaskKNN;
    namedWindow("input video", CV_WINDOW_AUTOSIZE);
    namedWindow("MOG2", CV_WINDOW_AUTOSIZE);
    namedWindow("KNN Model", CV_WINDOW_AUTOSIZE);

    //形态学开操作  
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));

    // intialization BS
    //高斯混合模型背景建模
    Ptr pMOG2 = createBackgroundSubtractorMOG2();
    //KNN-K个最近邻
    Ptr pKNN = createBackgroundSubtractorKNN();
    while (capture.read(frame)) {
        imshow("input video", frame);

        // MOG BS
        pMOG2->apply(frame, bsmaskMOG2);//
        //形态学开操作去噪点 
        //对处理后的帧进行开操作,减少视频中较小的波动造成的影响
        morphologyEx(bsmaskMOG2, bsmaskMOG2, MORPH_OPEN, kernel, Point(-1, -1));
        imshow("MOG2", bsmaskMOG2);//高斯混合模型背景模型

        // KNN BS mask
        pKNN->apply(frame, bsmaskKNN);
        morphologyEx(bsmaskKNN, bsmaskKNN, MORPH_OPEN, kernel, Point(-1, -1));//形态学开操作去噪点
        imshow("KNN Model", bsmaskKNN);//KNN背景模型
        char c = waitKey(50);
        if (c == 27) {
            break;
        }
    }

    capture.release();
    waitKey(0);
    return 0;
}


P111-P112基于颜色的对象检测与跟踪***单目标

/*思路:inRange过滤、形态学操作提取、轮廓查找、外接矩形获取、位置标定*/
#include
#include

using namespace cv;
using namespace std;

void processFrame(Mat& img, Rect& rect);//绘制外接矩形

int main(int argc, char** argv)
{
    Rect roi;//存储最大外接矩形的数据
    VideoCapture capture(0);//调用摄像头
    //VideoCapture capture;
    //capture.open("D:/test/video_006.mp4");
    if (!capture.isOpened())
    {
        cout << "视频文件未找到..." << endl;
        return -1;
    }
    Mat frame, dst;
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    Mat kernel_dilite = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
    while (capture.read(frame))
    {

        //筛选出绿色
        inRange(frame, Scalar(0, 127, 0), Scalar(120, 255, 120), dst);

        //开操作去噪点
        morphologyEx(dst, dst, MORPH_OPEN, kernel, Point(-1, -1), 1);
        //膨胀操作把飞盘具体化的显示出来
        dilate(dst, dst, kernel_dilite, Point(-1, -1), 2);
        imshow("output video", dst);
        processFrame(dst, roi);
        rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);
        imshow("input video", frame);
        char c = waitKey(50);
        if (c == 27)
        {
            break;
        }

    }
    capture.release();
    waitKey(0);
    return 0;
}

void processFrame(Mat & img, Rect & rect)
{
    //寻找外接轮廓
    vector>contours;
    vectorhierarchy;
    findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(-1, -1));
    double area = 0.0;
    if (contours.size() > 0)
    {
        for (size_t i = 0; i < contours.size(); i++)
        {
            double contours_Area = contourArea(contours[static_cast(i)]);//面积
            rect = boundingRect(contours[static_cast(i)]);//外接矩形
            if (contours_Area > area)
            {
                area = contours_Area;
            }
        }

    }
    else
    {
        rect.x = rect.y = rect.width = rect.height = 0;
    }
}

P113-P116 光流对象跟踪****移动对象跟踪

(1)稀疏光流KLT

代码1 CSDN论坛代码*****只有结果显示,没有图像显示
#include
#include
#include
#include
#include
#include  
#include 

using namespace cv::face;
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

Mat frame, gray;//当前帧
Mat prev_gray;//前一帧
vector features;//shi-tomasi角点检测-特征数据
vectorfpts[2];//保证当前帧和前一帧的特征点位置
vector iniPoints;
vectorstatus;//特征点跟踪成功标志位
vectorerrors;//跟踪时候区域误差和

void detectFeatures(Mat &inFrame, Mat &ingray)  // Shi-Tomas 角点检测
{
    double maxCorners = 5000;
    double qualitylevel = 0.01;
    double minDistance = 10;
    double blockSize = 3;
    double k = 0.04;
    goodFeaturesToTrack(ingray, features, maxCorners, qualitylevel, minDistance, Mat(), blockSize, false, k); // 算法很快,满足实时性要求
    cout << "detect features : " << features.size() << endl;
}

void drawFeature(Mat&inFrame) {//绘制特征点
    for (size_t t = 0; t < fpts[0].size(); t++) {
        circle(inFrame, fpts[0][t], 2, Scalar(0, 0, 255), 2);
    }
}
void drawTrackLines() // 在跟踪到的且移动了的特征点(光流)的开始跟踪的位置 到 当前跟踪到的位置之间绘制线段
{
    for (size_t t = 0; t < fpts[1].size(); t++)
    {
        line(frame, iniPoints[t], fpts[1][t], Scalar(0, 255, 0), 1, 8, 0); // 绘制线段
        circle(frame, fpts[1][t], 2, Scalar(0, 0, 255), 2, 8, 0);
    }
}
void KLTrackFeature() {//稀疏光流跟踪,KTL

    calcOpticalFlowPyrLK(prev_gray, gray, fpts[0], fpts[1], status, errors);
    int k = 0;//保存跟踪到的特征点数,最后将特征点的尺寸重新设置为k
    for (int i = 0; i < fpts[1].size(); i++) {
        double dist = abs(fpts[0][i].x - fpts[1][i].x) + abs(fpts[0][i].y - fpts[1][i].y);
        if (dist > 2 && status[i])//跟踪到的特征点,且距离移动了2以上的
        {
            iniPoints[k] = iniPoints[i];//将跟踪到的移动了的特征点在vector中连续起来,剔掉损失的和禁止不动的特征点(这些跟踪点在前面帧中)
            fpts[1][k++] = fpts[1][i];//同上(只是这些跟踪点在当前帧中)
        }
    }
    //保存特征点并绘制跟踪轨迹
    iniPoints.resize(k);
    fpts[1].resize(k);
    drawTrackLines();
    std::swap(fpts[1], fpts[0]);//交换,将此帧跟踪到特征点作为下一帧的待跟踪点
}

int main() {
    //VideoCapture capture;
    //capture.open("C:/Users/Administrator/Desktop/pic/3.avi");
    VideoCapture capture(0);//调用摄像头
    while (capture.read(frame)) {
        cvtColor(frame, gray, COLOR_BGR2GRAY);
        if (fpts[0].size() < 40) {//跟踪40个特征点,如果跟踪的时候损失了一些特征点,重新检测,追加
            detectFeatures(frame, gray);
            fpts[0].insert(fpts[0].end(), features.begin(), features.end());//追加带跟踪的特征点
            iniPoints.insert(iniPoints.end(), features.begin(), features.end());
        }
        else
        {
            cout << "tracjing........" << endl;
        }
        if (prev_gray.empty())
            gray.copyTo(prev_gray);//保存当前已帧,第一帧过完就不保存了
        KLTrackFeature();//稀疏光流跟踪,KLT
        drawFeature(frame);//绘制特征点
        //更新前一帧数据
        gray.copyTo(prev_gray);//只需要灰度图
        imshow("src", frame);
    }
    waitKey(0);
}

(2)代码2  贾志刚老师教学视频代码****有显示,成功

// 程序描述:来自OpenCV安装目录下Samples文件夹中的官方示例程序-利用光流法进行运动目标检测
//  描述:包含程序所使用的头文件和命名空间
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
//  描述:声明全局函数
void tracking(Mat &frame, Mat &output);
bool addNewPoints();
bool acceptTrackedPoint(int i);
//  描述:声明全局变量
string window_name = "optical flow tracking";
Mat gray;   // 当前图片
Mat gray_prev;  // 预测图片
vector points[2];  // point0为特征点的原来位置,point1为特征点的新位置
vector initial;    // 初始化跟踪点的位置
vector features;   // 检测的特征
int maxCount = 500; // 检测的最大特征数
double qLevel = 0.01;   // 特征检测的等级
double minDist = 10.0;  // 两特征点之间的最小距离
vector status;   // 跟踪特征的状态,特征的流发现为1,否则为0
vector err;
//输出相应信息和OpenCV版本-----
static void helpinformation()
{
    cout << "\n\n\t\t\t 光流法跟踪运动目标检测\n"
        << "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
        << "\n\n";
}

//main( )函数,程序入口
int main()
{
    Mat frame;
    Mat result;
    //加载使用的视频文件,放在项目程序运行文件下
    //VideoCapture capture("1.avi");
    VideoCapture capture(0);//调用摄像头
    //显示信息函数
    helpinformation();
    // 摄像头读取文件开关
    if (capture.isOpened())
    {
        while (true)
        {
            capture >> frame;

            if (!frame.empty())
            {
                tracking(frame, result);
            }
            else
            {
                printf(" --(!) No captured frame -- Break!");
                break;
            }
            int c = waitKey(50);
            if ((char)c == 27)
            {
                break;
            }
        }
    }
    return 0;
}

// parameter: frame 输入的视频帧
//            output 有跟踪结果的视频帧
void tracking(Mat &frame, Mat &output)
{
    cvtColor(frame, gray, CV_BGR2GRAY);
    frame.copyTo(output);
    // 添加特征点
    if (addNewPoints())
    {
        goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
        points[0].insert(points[0].end(), features.begin(), features.end());
        initial.insert(initial.end(), features.begin(), features.end());
    }

    if (gray_prev.empty())
    {
        gray.copyTo(gray_prev);
    }
    // l-k光流法运动估计
    calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
    // 去掉一些不好的特征点
    int k = 0;
    for (size_t i = 0; i < points[1].size(); i++)
    {
        if (acceptTrackedPoint(i))
        {
            initial[k] = initial[i];
            points[1][k++] = points[1][i];
        }
    }
    points[1].resize(k);
    initial.resize(k);
    // 显示特征点和运动轨迹
    for (size_t i = 0; i < points[1].size(); i++)
    {
        line(output, initial[i], points[1][i], Scalar(0, 0, 255));
        circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);
    }

    // 把当前跟踪结果作为下一此参考
    swap(points[1], points[0]);
    swap(gray_prev, gray);
    imshow(window_name, output);
}

//  检测新点是否应该被添加
// return: 是否被添加标志
bool addNewPoints()
{
    return points[0].size() <= 10;
}

//决定哪些跟踪点被接受
bool acceptTrackedPoint(int i)
{
    return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
}


P117-P120 CAMShift 对象跟踪(对象跟踪扩展模块)

(1)教学视频相关代码---CAMShift 算法对象跟踪介绍:均值计算,密度最高点跟踪

#include
#include
#include
#include

using namespace cv;
using namespace std;

//HSV颜色范围
int smin = 40;
int vmin = 40;
int smax = 255;
int vmax = 255;


int bins = 16;

int main(int agrc, char** argv)
{
    //VideoCapture capture;
    //capture.open("视频路径");
    VideoCapture capture(0);//调用摄像头

    if (!capture.isOpened())
    {
        printf("could not find video data file...\n");
        return -1;
    }
    namedWindow("CAMShift Tracking", CV_WINDOW_AUTOSIZE);
    namedWindow("ROI Histogram", CV_WINDOW_AUTOSIZE);

    bool firstRead = true;
    float hrange[] = { 0,180 };
    const float* hranges = hrange;
    Rect selection;
    Mat frame, hsv, hue, mask, hist, backprojection;
    Mat drawImg = Mat::zeros(300, 300, CV_8UC3);

    while (capture.read(frame))
    {
        if (firstRead)
        {
            Rect2d first = selectROI("CAMShift Tracking", frame);
            selection.x = first.x;
            selection.y = first.y;
            selection.width = first.width;
            selection.height = first.height;
            printf("ROL.x =%d, ROL.y =%d, width =%d, height =%d", selection.x, selection.y, selection.width, selection.height);
            //firstRead = false;
        }


        //convert to HSV
        cvtColor(frame, hsv, COLOR_BGR2HSV);
        inRange(hsv, Scalar(0, smin, vmin), Scalar(180, smax, vmax), mask);//筛选颜色
        hue = Mat(hsv.size(), hsv.depth());
        int channels[] = { 0,0 };
        mixChannels(&hsv, 1, &hue, 1, channels, 1);


        if (firstRead)
        {
            //calculate histogram -ROI直方图计算
            Mat roi(hue, selection);
            Mat maskroi(mask, selection);
            calcHist(&roi, 1, 0, maskroi, hist, 1, &bins, &hranges);
            normalize(hist, hist, 0, 255, NORM_MINMAX);


            //show histogram
            int binw = drawImg.cols / bins;
            Mat colorIndex = Mat(1, bins, CV_8UC3);
            for (int i = 0; i < bins; i++)
            {
                colorIndex.at(0, i) = Vec3b(saturate_cast(i * 180 / bins), 255, 255);

            }
            cvtColor(colorIndex, colorIndex, COLOR_HSV2BGR);
            for (int i = 0; i < bins; i++)
            {
                int val = saturate_cast(hist.at(i)*drawImg.rows / 255);
                rectangle(drawImg, Point(i*binw, drawImg.rows), Point((i + 1)*binw, drawImg.rows - val), Scalar(colorIndex.at(0, i)), -1, 8, 0);

            }
        }
        //back projection
        calcBackProject(&hue, 1, 0, hist, backprojection, &hranges);

        //CAMShift tracking
        backprojection &= mask;
        RotatedRect trackBox = CamShift(backprojection, selection, TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1));

        // draw location on frame
        ellipse(frame, trackBox, Scalar(0, 0, 255), 3, 8);//绘制红色椭圆,BGR
        if (firstRead)
        {
            firstRead = false;
        }
        imshow("CAMShift Tracking", frame);
        imshow("ROI Histogram", drawImg);
        char c = waitKey(50);//ESC
        if (c == 27)
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}


(2) CSDN相应代码-CAMShift 算法对象跟踪*******跟踪效果极好
//Select a ROI and then press SPACE or ENTER button!
//Cancel the selection process by pressing c button!

#include
#include

using namespace cv;
using namespace std;
//HSV
int smin = 30;
int smax = 255;
int vmin = 40;
int vmax = 255;
//calcHist参数
int histSize = 16;//区间的个数
float hue_ranges[] = { 0,180 };
const float* ranges = hue_ranges;


int main(int argc, char** argv)
{
    VideoCapture capture;
    //capture.open(0);

    capture.open(0);
    if (!capture.isOpened())
    {
        cout << "could not load video..." << endl;
        return -1;
    }

    bool firstRead = true;//用于判断是否第一次读取视频


    Rect selection;//selectROI用鼠标选择的ROI区域
    Mat frame, blur, hsv, mask, hue, temp_histogram, backprojection;
    Mat Histogram = Mat::zeros(300, 300, CV_8UC3);
    namedWindow("CAMShift Tracking", WINDOW_AUTOSIZE);
    while (capture.read(frame))
    {
        if (firstRead)
        {
            //获取第一帧的ROI区域
            Rect2d first_img = selectROI("CAMShift Tracking", frame);//在"CAMShift Tracking"窗口的frame图像上用鼠标选择ROI区域
            selection.x = first_img.x;
            selection.y = first_img.y;
            selection.width = first_img.width;
            selection.height = first_img.height;
            cout << "ROI的x值为:        " << selection.x << endl;
            cout << "ROI的y值为:        " << selection.y << endl;
            cout << "ROI的width值为:    " << selection.width << endl;
            cout << "ROI的height值为:    " << selection.height << endl;

        }


        GaussianBlur(frame, blur, Size(5, 5), 3, 3);//使用高斯滤波进行去噪
        cvtColor(blur, hsv, COLOR_BGR2HSV);//转换到HSV空间
        //测试矩阵frame的元素是否在其他两个矩阵的值之间//提取黄色
        inRange(hsv, Scalar(0, smin, vmin), Scalar(180, smax, vmax), mask);

        hue = Mat(hsv.size(), hsv.depth());
        int channels[] = { 0,0 };//fromto映射//指定被复制通道与要复制到的位置组成的索引对
        size_t npairs = 1; //指定被复制通道与要复制到的位置channels[]组成的索引对
        mixChannels(&hsv, 1, &hue, 1, channels, npairs);    //输入矩阵通道 重新排列到 输出矩阵通道(HSV中的H值)

        if (firstRead)
        {
            //计算ROI直方图
            Mat ROI(hue, selection);//Mat& image , Rect& roi
            Mat MaskROI(mask, selection);
            calcHist(&ROI, 1, 0, MaskROI, temp_histogram, 1, &histSize, &ranges);//计算直方图
            normalize(temp_histogram, temp_histogram, 0, 255, NORM_MINMAX);//归一化

            //显示直方图图像
            int bins = Histogram.cols / histSize; //300/16 = 18.5 单个区间宽度
            //定义一个缓冲单bins矩阵,1行16列,用于存放颜色数据,用于直方图histSize个bin的“染色”
            Mat ColorIndex = Mat(1, histSize, CV_8UC3);//1行histSize=16列
            for (int i = 0; i < histSize; i++)
            {
                ColorIndex.at(0, i) = Vec3b(saturate_cast(i * 180 / histSize), 255, 255);//只是为了好看
            }
            cvtColor(ColorIndex, ColorIndex, COLOR_HSV2BGR);
            for (int j = 0; j < histSize; j++)
            {
                //value是直方图temp_histogram的相对Histogram的高度
                //temp_histogram.at(i)获取了第i个bin直方图数据,除以255后得到百分比
                //再乘以Histogram的行数就得到了相对高度,最后进行int的强制类型转换,转换为整数。
                int  value = saturate_cast(temp_histogram.at(j) * Histogram.rows / 255);
                //之后使用rectangle()函数进行16个bin的绘制
                //值得注意的是矩阵的坐标系以左上角为原点,y轴是向下的
                //而需要展示给人看的直方图图案是左下角为原点,y轴向上的
                //因此rectangle的两个标定点的纵坐标是Histogram.rows和(Histogram.rows - val)而不是0和val
                rectangle(Histogram,
                    Point(j * bins, Histogram.rows), //矩阵对角点:左下角
                    Point((j + 1) * bins, Histogram.rows - value), //矩阵对角点:右上角
                    Scalar(ColorIndex.at(0, j)), -1, 8, 0);
            }
            firstRead = false;//需要绘制第一帧的直方图
        }

        //直方图反向投影
        /*void calcBackProject(
            const Mat* images,  //输入的数组
            int nimages,        //输入数组的个数
            const int* channels,    //需要统计的通道索引
            InputArray hist,    //输入的直方图
            OutputArray backProject,//目标的反向投影
            const float** ranges,   //每一位数值的取值范围
            double scale=1,     //输出方向投影的缩放因子
            bool uniform=true   //指示直方图是否均匀的标识符
            )
        */
        //用来计算像素和直方图模型中像素吻合度的方法
        calcBackProject(&hue, 1, 0, temp_histogram, backprojection, &ranges);
        backprojection &= mask;//a&=b 即 a=a&b  其中&为位与运算//给b取了一个别名叫a,所有对b的操作都是直接作用于a

        //CAMShift
        RotatedRect trackBox = CamShift(
            backprojection, //反向投影
            selection,//矩形搜索框
            TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1));//迭代中止条件

        //绘制位置更新显示在frame上

        //---------------------------------获取CamShift的返回值,是一个旋转矩形,以下为绘制跟踪结果的部分
        ellipse(frame, trackBox, Scalar(255, 0, 255), 3, 8);//根据旋转矩形绘制一个椭圆形显示在图像上作为追踪结果。
        Point2f vertices[4];//定义存储4个x,y变量的数组
        trackBox.points(vertices);//将旋转矩形的四个顶点值传入数组 
        for (int i = 0; i < 4; i++)//绘制旋转矩形的四条边
            line(frame, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0));
        Rect brect = trackBox.boundingRect();//返回最小旋转角度为0的外接矩形
        rectangle(frame, brect, Scalar(255, 0, 0));//绘制外接矩形
        //----------------------------------


        if (firstRead)
        {
            firstRead = false;
        }

        imshow("CAMShift Tracking", frame);
        imshow("Histogram", Histogram);


        char c = waitKey(1);
        if (c == 27)
        {
            break;
        }
    }

    capture.release();
    waitKey(0);
    //destroyAllWindows();
    return 0;
}


P121视频中移动对象统计:也即统计移动物体的数量******项目可以考虑

(1) 教学视频代码演示****效果好
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    //VideoCapture capture;
    //capture.open("读取视频地址");
    VideoCapture capture(0);//调用摄像头
    if (!capture.isOpened())
    {
        printf("could not load video data...\n");
        return -1;
    }
    namedWindow("input video", CV_WINDOW_AUTOSIZE);
    namedWindow("motion objects", CV_WINDOW_AUTOSIZE);

    //初始BS模型
    PtrpMOG2 = createBackgroundSubtractorMOG2();
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));

    vector> contours;
    vector hireachy;
    int count = 0;
    Mat frame, gray,mogMask;
    while (capture.read(frame))
    {
        imshow("input video", frame);
        pMOG2->apply(frame, mogMask);
        threshold(mogMask, mogMask, 100, 255, THRESH_BINARY);
        morphologyEx(mogMask, mogMask, MORPH_OPEN, kernel, Point(-1, -1));

        findContours(mogMask, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
        count = 0;
        char numText[8];
        for (size_t t = 0; t < contours.size(); t++)
        {
            double area = contourArea(contours[t]);
            if (area < 1000) continue;
            Rect selection = boundingRect(contours[t]);
            if (selection.width < 30 || selection.height < 30) continue;
            count++;
            rectangle(frame, selection, Scalar(0, 0, 255), 2, 8);

            sprintf_s(numText, "%d", count);
            putText(frame, numText, Point(selection.x, selection.y), CV_FONT_NORMAL, FONT_HERSHEY_PLAIN, Scalar(255,0,0),1, 8);


        }
        imshow("motion objects", frame);
        char c = waitKey(50);
        if (c == 27)//ESC
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}

(2)CSDN代码-视频中移动对象统计

#include
#include
#include
#include
#include
#include  
#include 

using namespace cv::face;
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;

int main() {
    //VideoCapture capture;
    //capture.open("C:/Users/Administrator/Desktop/pic/3.avi");
    VideoCapture capture(0);//调用摄像头
    PtrpMOG2 = createBackgroundSubtractorMOG2();
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    vector>contours;
    vector hireachy;
    Mat frame, gray, mogmask;
    while (capture.read(frame)) {
        imshow("src", frame);
        pMOG2->apply(frame, mogmask);
        threshold(mogmask, mogmask, 100, 255, THRESH_BINARY);//二值化
        morphologyEx(mogmask, mogmask, MORPH_OPEN, kernel);
        findContours(mogmask, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
        cvtColor(mogmask, mogmask, COLOR_GRAY2BGR);
        int count = 0;
        char numText[8];
        for (size_t t = 0; t < contours.size(); t++) {
            double area = contourArea(contours[t]);//获取轮廓的面积
            if (area < 100) continue;//忽略面积小的
            Rect selection = boundingRect(contours[t]);
            if (selection.width < 10 || selection.height < 10) contours;
            count++;
            rectangle(mogmask, selection, Scalar(0, 0, 255), 2);
            sprintf_s(numText, "%d", count);
            putText(mogmask, numText, Point(selection.x, selection.y), CV_FONT_NORMAL, FONT_HERSHEY_PLAIN, Scalar(255, 0, 0));
        }
        imshow("motion objects", mogmask);
        char c = waitKey(50);
        if (c == 27)//ESC
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}


P122、 扩展模块中的跟踪方法介绍2021/1/20*****可以和上面的CamShift跟踪算法对比---单目标检测算法对比
KCF、BOOSTING、MIL、MEDIANFLOW、TLD跟踪算法

#include
#include
#include

using namespace cv;
using namespace std;

int main(int agrc, char** agrv)
{
    //VideoCapture capture;
    //capture.open("视频路径");

    VideoCapture capture(0);//调用摄像头

    if (!capture.isOpened())
    {
        printf("could not load video data...\n");
        return -1;
    }
    Mat frame;
    namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
    Ptr tracker = TrackerKCF::create();//KCF跟踪算法
    //Ptr tracker = TrackerBoosting::create();//BOOSTING跟踪算法
    //Ptr tracker = TrackerMIL::create();//MIL跟踪算法
    //Ptr tracker = TrackerMedianFlow::create();//MEDIANFLOW跟踪算法
    //Ptr tracker = TrackerTLD::create();//TLD跟踪算法

    capture.read(frame);
    Rect2d roi = selectROI("tracker demo", frame);
    if (roi.width == 0 || roi.height == 0)
    {
        return -1;
    }
    tracker->init(frame, roi);
    while (capture.read(frame))
    {
        tracker->update(frame, roi);
        rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
        imshow("tracker demo", frame);
        char c = waitKey(20);
        if (c == 27)
        {
            break;
        }
    }

    capture.release();
    waitKey(0);
    return 0;

}

P123、多对象目标跟踪******实际项目常用
(1) 、CSDN论坛上的多目标跟踪MultiTrack****成功

#include
#include
#include
#include
#include
#include
#include

using namespace std;
using namespace cv;

inline cv::Ptr createTrackerByName(cv::String name)
{
    cv::Ptr tracker;

    if (name == "KCF")
        tracker = cv::TrackerKCF::create();
    else if (name == "TLD")
        tracker = cv::TrackerTLD::create();
    else if (name == "BOOSTING")
        tracker = cv::TrackerBoosting::create();
    else if (name == "MEDIAN_FLOW")
        tracker = cv::TrackerMedianFlow::create();
    else if (name == "MIL")
        tracker = cv::TrackerMIL::create();
    else if (name == "GOTURN")
        tracker = cv::TrackerGOTURN::create();
    else if (name == "MOSSE")
        tracker = cv::TrackerMOSSE::create();
    else if (name == "CSRT")
        tracker = cv::TrackerCSRT::create();
    else
        CV_Error(cv::Error::StsBadArg, "Invalid tracking algorithm name\n");

    return tracker;
}
int main(int argc, char** argv) {


    // set the default tracking algorithm
    std::string trackingAlg = "MEDIAN_FLOW";

    MultiTracker trackers;

    // container of the tracked objects

    vector objects;

    VideoCapture cap(0);

    if (!cap.isOpened())
    {
        std::cout << "error open." << std::endl;
        return -1;
    }

    Mat frame;

    // get bounding box
    cap >> frame;
    //! [selectmulti]
    vector ROIs;

    selectROIs("tracker", frame, ROIs);
    //! [selectmulti]

    //quit when the tracked object(s) is not provided
    if (ROIs.size() < 1)
        return 0;

    // initialize the tracker
    //! [init]
    std::vector > algorithms;
    for (size_t i = 0; i < ROIs.size(); i++)
    {
        algorithms.push_back(createTrackerByName(trackingAlg));
        objects.push_back(ROIs[i]);
    }

    trackers.add(algorithms, frame, objects);
    //! [init]

    // do the tracking
    printf("Start the tracking process, press ESC to quit.\n");

    while (cap.isOpened()) {

        cap >> frame;

        //update the tracking result
        trackers.update(frame);

        // draw the tracked object
        for (unsigned i = 0; i < trackers.getObjects().size(); i++)
            rectangle(frame, trackers.getObjects()[i], Scalar(0, 0, 255), 2, 1);//BGR

        // show image with the tracked object
        imshow("tracker", frame);

        //quit on ESC button
        if (waitKey(1) == 27)break;
    }

}


(2)、教学视频贾志刚改写的多目标跟踪算法****成功

//先框选目标,按空格或者ENTER键确认,依次选择,选择完成后按ESC键
#include
#include
#include


using namespace cv;
using namespace std;

inline cv::Ptr createTrackerByName(cv::String name)//自定义多目标函数所要选用的跟踪算法函数
{
    cv::Ptr tracker;

    if (name == "KCF")
        tracker = cv::TrackerKCF::create();
    else if (name == "TLD")
        tracker = cv::TrackerTLD::create();
    else if (name == "BOOSTING")
        tracker = cv::TrackerBoosting::create();
    else if (name == "MEDIAN_FLOW")
        tracker = cv::TrackerMedianFlow::create();
    else if (name == "MIL")
        tracker = cv::TrackerMIL::create();
    else if (name == "GOTURN")
        tracker = cv::TrackerGOTURN::create();
    else if (name == "MOSSE")
        tracker = cv::TrackerMOSSE::create();
    else if (name == "CSRT")
        tracker = cv::TrackerCSRT::create();
    else
        CV_Error(cv::Error::StsBadArg, "Invalid tracking algorithm name\n");

    return tracker;
}
int main(int agrc, char ** agrv)
{
    //VideoCapture capture;
    //capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");

    VideoCapture capture(0);//打开摄像头
    std::string trackingAlg = "MEDIAN_FLOW";//选择多目标算法,当前选用的是Median_Flow跟踪算法作为多目标跟踪算法

    if (!capture.isOpened())
    {
        printf("could not load data....\n");
        return -1;
    }
    //namedWindow("Multiple Objects Tracking-1", CV_WINDOW_AUTOSIZE);
    MultiTracker trackers ;//定义多目标对象trackers
    vector ROIs;

    Mat frame;
    capture.read(frame);
    selectROIs("Multiple Objects Tracking", frame, ROIs);//绘制选定目标
    if (ROIs.size() < 1)
    {
        return -1;
    }
    
    std::vector > algorithms;
    vector objects;
    for (size_t i = 0; i < ROIs.size(); i++)
    {
        algorithms.push_back(createTrackerByName(trackingAlg));//调用多目标算法函数,此时的trackingAlg代表多目标跟踪具体选用的跟踪算法
        objects.push_back(ROIs[i]);
    }

    
    trackers.add(algorithms, frame, objects);
    while (capture.read(frame))
    {
        trackers.update(frame);
        for (size_t t = 0; t < trackers.getObjects().size(); t++)
        {
            rectangle(frame, trackers.getObjects()[t], Scalar(0, 0, 255), 2, 8, 0);

        }
        imshow("Multiple Objects Tracking", frame);
        char c = waitKey(50);
        if (c == 27)
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return -1;
}


P124 DNN模块概述2021/1/21--深度学习模块***
P125 -P126 GooleNet模型实现图像数据分类

(1)、CSDN读入图片的GOOLENet实现图像分类代码:成功
#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::dnn;

string caffe_model_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel";  //训练文件
string caffe_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt";   //描述文件
string labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt";   //标签文件
vector readClassLabels();//定义读取文件每行的函数

int main(int argc, char** argv)
{
    Mat src = imread("C:/Users/25503/Desktop/123.png");
    if (src.empty())
    {
        cout << "图片未找到!!!" << endl;
        return -1;
    }
    //imshow("input image", src);
    vector labels = readClassLabels();
    Net caffe_net = readNetFromCaffe(caffe_txt_file, caffe_model_file);

    if (caffe_net.empty())
    {

        return -1;
    }

    Mat inputblob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123)); //将读进来的图像转为blob
    Mat prob;


    caffe_net.setInput(inputblob, "data");//第一层是data
    prob = caffe_net.forward("prob");


    Mat Matprob = prob.reshape(1, 1); //维度变成1*1000
    double Probability;   //最大相似度
    Point classindex;


    minMaxLoc(Matprob, NULL, &Probability, NULL, &classindex);
    int Nameindex = classindex.x;     //最大相似度对应的索引
    cout << "Probability:" << Probability * 100 << "%" << endl;
    cout << "NameValue:" << labels.at(Nameindex) << endl;
    putText(src, labels.at(Nameindex), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);

    imshow("result image", src);


    waitKey(0);
    return 0;

}

vector readClassLabels()
{
    vectorclassNames;  //存放name
    ifstream fp(labels_txt_file);//读入文件
    if (!fp.is_open())
    {
        cout << "文件未找到!!!" << endl;
        exit(-1);
    }
    string name;
    while (!fp.eof())  //当文件没有读到尾部
    {
        getline(fp, name); //读取文件每一行,从fp中读取,将结果放在name里面去
        if (name.length())
        {
            classNames.push_back(name.substr(name.find(" ") + 1)); //从空格后面开始取字符

        }
    }
    fp.close();//关闭输入输出流
    return classNames;
}


(2)、CSDN读入视频/摄像头的GooleNet实现图像分类代码:成功

#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::dnn;

string caffe_model_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel";  //训练文件
string caffe_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt";   //描述文件
string labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt";   //标签文件
vector readClassLabels();//定义读取文件每行的函数

int main(int argc, char** argv)
{
    Mat frame;
    VideoCapture capture(0);//打开摄像头
    //Mat src = imread("D:/test/cat.jpg");
    if (!capture.isOpened())
    {
        cout << "摄像头未找到!!!" << endl;
        return -1;
    }
    //imshow("input image", src);
    vector labels = readClassLabels();
    Net caffe_net = readNetFromCaffe(caffe_txt_file, caffe_model_file);

    if (caffe_net.empty())
    {

        return -1;
    }
    Mat inputblob;
    Mat prob, Matprob;
    double Probability;   //最大相似度
    Point classindex;
    while (capture.read(frame))
    {
        inputblob = blobFromImage(frame, 1.0, Size(224, 224), Scalar(104, 117, 123)); //将读进来的图像转为blob
        caffe_net.setInput(inputblob, "data");//第一层是data
        prob = caffe_net.forward("prob");
        Matprob = prob.reshape(1, 1); //维度变成1*1000
        minMaxLoc(Matprob, NULL, &Probability, NULL, &classindex);
        int Nameindex = classindex.x;     //最大相似度对应的索引
        cout << "Probability:" << Probability * 100 << "%" << endl;
        cout << "NameValue:" << labels.at(Nameindex) << endl;
        putText(frame, labels.at(Nameindex), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);
        imshow("result image", frame);
        char c = waitKey(5);
        if (c == 27)
        {
            break;
        }
    }


    waitKey(0);
    return 0;

}

vector readClassLabels()
{
    vectorclassNames;  //存放name
    ifstream fp(labels_txt_file);//读入文件
    if (!fp.is_open())
    {
        cout << "文件未找到!!!" << endl;
        exit(-1);
    }
    string name;
    while (!fp.eof())  //当文件没有读到尾部
    {
        getline(fp, name); //读取文件每一行,从fp中读取,将结果放在name里面去
        if (name.length())
        {
            classNames.push_back(name.substr(name.find(" ") + 1)); //从空格后面开始取字符

        }
    }
    fp.close();//关闭输入输出流
    return classNames;
}


(3)、教学视频读入图片的GooleNet实现图像分类代码:成功

#include
#include //神经网络头文件
#include

using namespace cv;
using namespace cv::dnn;
using namespace std;

String model_bin_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel";//训练文件
String model_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt";//描述文件
String labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt";//标签文件

vector readLabels();

int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/12345.jpg");//读入图片
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);

    vector labels = readLabels();//图片标记函数
    Net net = readNetFromCaffe(model_txt_file, model_bin_file);//神经网络函数调用
    if (net.empty())
    {
        printf("read caffe model data failure...\n");
        return -1;
    }
    Mat inputBlob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123));
    Mat prob;
    for (int i = 0; i < 10; i++)
    {
        net.setInput(inputBlob, "data");
        prob = net.forward("prob");
    }
    Mat probMat = prob.reshape(1, 1);
    Point classNumber;
    double classProb;
    minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber);
    int classidx = classNumber.x;
    printf("\n current image classification :%s, possible :%.2f", labels.at(classidx).c_str(), classProb);

    //putText(src, labels.at(classidx), Point(20, 20), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 2, 8);//在读取的图片标记神经网络分类后的字体
    putText(src, labels.at(classidx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);
    imshow("Image Classification", src);
    waitKey(0);
    return 0;

}
vector readLabels()
{
    vector classNames;
    ifstream fp(labels_txt_file);
    if (!fp.is_open())
    {
        printf("could not open the file");
        exit(-1);
    }
    string name;
    while (!fp.eof())
    {
        getline(fp, name);
        if (name.length())
        {
            classNames.push_back(name.substr(name.find(' ') + 1));//按照标签文件处理图片
        }
    }
    fp.close();
    return classNames;
}


P127-P128 深度神经网络SSD模型实现图像检测*****成功

(1)CSDN 上的SSD神经网络代码:成功,但需要训练标签文件
#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::dnn;

const size_t width = 300;
const size_t height = 300;//定义图像文件宽高

vector labels();

string label_file = "D:/OpenCV神经网络2/SSD神经网络/labelmap_det.txt";//标签文件
string deploy_file = "D:/OpenCV神经网络2/SSD神经网络/deploy.txt";//描述文件
string model_file = "D:/OpenCV神经网络2/SSD神经网络/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel";

int main(int argc, char **argv)
{
    Mat src = imread("C:/Users/25503/Desktop/12345.jpg");
    if (src.empty())
    {

        cout << "图像未找到!!!" << endl;
        return -1;
    }
    vector  objnames = labels();
    namedWindow("input image", WINDOW_AUTOSIZE);
    imshow("input image", src);
    Net net = readNetFromCaffe(deploy_file, model_file);
    Mat frame;
    src.copyTo(frame);
    if (frame.channels() == 4)
    {
        cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
    }

    if (frame.channels() == 1)
    {
        cvtColor(frame, frame, COLOR_GRAY2BGR);//将单通道转为3通道

    }

    Mat blob_Img = blobFromImage(frame, 1.0f, Size(width, height), Scalar(104, 117, 123), false, false);
    net.setInput(blob_Img, "data");//开始层
    Mat detection = net.forward("detection_out");//最后一层

    Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr());
    /*
    detection.size[2]表示宽度
    detection.size[3]表示高度
    */

    float confidence_threshold = 0.2;

    for (int i = 0; i < detectionMat.rows; i++)
    {
        float confidence = detectionMat.at(i, 2);    //置信度
        if (confidence > confidence_threshold) {
            size_t objIndex = (size_t)(detectionMat.at(i, 1));  //标签文件的索引号
            float tl_x = detectionMat.at(i, 3) * frame.cols;  //矩形框左上横坐标点
            float tl_y = detectionMat.at(i, 4) * frame.rows;  //矩形框左上纵坐标点
            float br_x = detectionMat.at(i, 5) * frame.cols;  //矩形框右下横坐标点
            float br_y = detectionMat.at(i, 6) * frame.rows;  //矩形框右下纵坐标点

            Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
            rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
            putText(frame, format("%s", objnames[objIndex].c_str()), Point(tl_x + 1, tl_y + 1), FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 0), 2);
            //cout << objIndex << endl;
        }
    }
    imshow("output image", frame);

    waitKey(0);
    return 0;

}

vector labels()
{
    vectorobjNames;


    ifstream fp(label_file);//打开输入流,读入文件
    if (!fp.is_open())
    {
        printf("文件读入失败!!!\n");
        exit(-1);//直接退出

    }
    string name;//标签文件中都有对应的名字
    while (!fp.eof())//当文件没有读到结尾
    {
        getline(fp, name);//读取每一行
        if (name.length())
        {
            string temp1 = name.substr(name.find(",") + 1);   //找到每行第一个逗号,从逗号后面开始取数据
            string temp2 = temp1.substr(temp1.find(",") + 1);//找到新的(第二个)逗号,从逗号后面开始取数据
            objNames.push_back(temp2);
        }
    }
    /*for (vector::iterator iter = objNames.begin(); iter != objNames.end(); ++iter)
    {
        //输出*iter才是输出那些字符串
        cout << *iter << endl;
    }*/
    return objNames;
}

(2)教学视频上的SSD对象检测代码:失败,可能因为Caffe模型找的不正确


#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::dnn;

const size_t width = 300;
const size_t height = 300;
String labelFile = "D:/OpenCV神经网络2/SSD神经网络/labelmap_det.txt";//标签文件
String modelFile = "D:/OpenCV神经网络2/SSD神经网络/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel";//模型文件
String model_text_file = "D:/OpenCV神经网络2/SSD神经网络/deploy.txt";//描述文件

vector readLabels();
const int meanValues[3] = { 104,117,123 };
static Mat getMean(const size_t &w, const size_t &h)
{
    Mat mean;
    vector channels;
    for (int i = 0; i < 3; i++)
    {
        Mat channel(h, w, CV_32F, Scalar(meanValues[i]));
        channels.push_back(channel);
    }
    merge(channels, mean);
    return mean;
}

static Mat preprocess(const Mat &frame)
{
    Mat preprocessed;
    frame.convertTo(preprocessed, CV_32F);
    resize(preprocessed, preprocessed, Size(width, height));//300x300 image
    Mat mean = getMean(width, height);
    subtract(preprocessed, mean, preprocessed);
    return preprocessed;
}
int main(int agrc, char** agrv)
{
    Mat src = imread("C:/Users/25503/Desktop/12345.jpg");
    if (src.empty())
    {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);
    vector objNames = readLabels();

    //import Caffe SSD model
    Net net = readNetFromCaffe(model_text_file, modelFile);
    Mat frame;
    src.copyTo(frame);
    if (frame.channels() == 4)
    {
        cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
    }

    if (frame.channels() == 1)
    {
        cvtColor(frame, frame, COLOR_GRAY2BGR);//将单通道转为3通道

    }

    Mat input_imahe = preprocess(frame);
    Mat bloImage = blobFromImage(input_imahe);

    net.setInput(bloImage,"data");
    Mat detection = net.forward("detection_out");
    Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr());
    float confidence_threshold = 0.1;
    //float confidence_threshold = 0.2;
    for (int i = 0; i < detectionMat.rows; i++)
    {
        float confidence = detectionMat.at(i, 2);
        if (confidence > confidence_threshold)
        {
            size_t objIndex = (size_t)(detectionMat.at(i, 1));
            float t1_x = detectionMat.at(i, 3) *frame.cols;
            float t1_y = detectionMat.at(i, 4) *frame.rows;
            float br_x = detectionMat.at(i, 5) *frame.cols;
            float br_y = detectionMat.at(i, 6) *frame.rows;

            Rect object_box((int)t1_x, (int)t1_y, (int)(br_x - t1_x), (int)(br_y - t1_y));
            rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
            putText(frame, format("%s",objNames[objIndex].c_str()), Point(t1_x, t1_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);

        }
    }
    imshow("ssd-demo", frame);
    waitKey(0);
    return 0;
}
vector readLabels()
{
    vector objNames;
    ifstream fp(labelFile);
    if (!fp.is_open())
    {
        printf("could not open the file...\n");
        exit(-1);
    }
    string name;
    while (!fp.eof())
    {
        getline(fp, name);
        if (name.length() && (name.find("display_name:") == 0))
        {
            string temp = name.substr(15);
            temp.replace(temp.end() - 1, temp.end(), "");
            objNames.push_back(temp);
        }
    }
    return objNames;
}

P129 MobileNet-SSD深度神经网络对象检测*****成功,极好

(1)、CSDN上的MobileNet-SSD目标对象检测(注意:MobileNet-SSD可以检测到具体到需要的对象,而单纯SSD只要在标签对象里面都能检测出来,根据实际需要选择检测方法)

#include
#include
#include

using namespace cv;
using namespace cv::dnn;
using namespace std;

const size_t width = 300;
const size_t height = 300;
const float meanVal = 127.5;//均值
const float scaleFactor = 0.007843f;
const char* classNames[] = { "background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor" };
//模型文件
String modelFile = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.caffemodel";
//二进制描述文件
String model_text_file = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.txt";

int main(int argc, char** argv) {
    VideoCapture capture;//读取视频
    capture.open(0);
    namedWindow("input", CV_WINDOW_AUTOSIZE);
    int w = capture.get(CAP_PROP_FRAME_WIDTH);//获取视频宽度
    int h = capture.get(CAP_PROP_FRAME_HEIGHT);//获取视频高度
    printf("frame width : %d, frame height : %d", w, h);

    // set up net
    Net net = readNetFromCaffe(model_text_file, modelFile);

    Mat frame;
    while (capture.read(frame)) {
        imshow("input", frame);

        // 预测
        Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
        net.setInput(inputblob, "data");
        Mat detection = net.forward("detection_out");

        // 绘制
        Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr());
        float confidence_threshold = 0.25;//自信区间,越小检测到的物体越多(>=0.25)
        for (int i = 0; i < detectionMat.rows; i++) {
            float confidence = detectionMat.at(i, 2);
            if (confidence > confidence_threshold) {
                size_t objIndex = (size_t)(detectionMat.at(i, 1));
                float tl_x = detectionMat.at(i, 3) * frame.cols;
                float tl_y = detectionMat.at(i, 4) * frame.rows;
                float br_x = detectionMat.at(i, 5) * frame.cols;
                float br_y = detectionMat.at(i, 6) * frame.rows;

                Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
                rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
                putText(frame, format("%s", classNames[objIndex]), Point(tl_x, tl_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
            }
        }
        imshow("ssd-video-demo", frame);
        char c = waitKey(5);
        if (c == 27) { // 如果ESC按下
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}


(2)、教学视频上的MobileNet-SSD目标对象检测代码:效果极好

#include
#include
#include

using namespace cv;
using namespace cv::dnn;
using namespace std;

const size_t width = 300;
const size_t height = 300;
const float meanVal = 127.5;
const float scaleFactor = 0.007843f;
const char* classNames[] = { "background",
    "aeroplane","bicycle","bird","boat",
    "bottle","bus","car","cat","chair",
    "cow","diningtable","dog","horse",
    "motorbike","person","pottedplant",
    "sheep","sofa","train","tvmonitor"
};

String modelFile = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.caffemodel";
String model_text_file = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.txt";
 
int main(int agrc, char** agrv)
{
    VideoCapture capture(0);
    namedWindow("input", CV_WINDOW_AUTOSIZE);

    int w = capture.get(CAP_PROP_FRAME_WIDTH);
    int h = capture.get(CAP_PROP_FRAME_HEIGHT);
    printf("frame width :%d,frame height :%d", w, h);

    //set up net
    Net net = readNetFromCaffe(model_text_file, modelFile);

    Mat frame;
    while (capture.read(frame))
    {
        imshow("input", frame);

        //预测
        Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
        net.setInput(inputblob, "data");
        Mat detection = net.forward("detection_out");
        
        //绘制
        Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr());
        float confidence_threshold = 0.2;
        //float confidence_threshold = 0.25;
        //float confidence_threshold = 0.5;

        for (int i = 0; i < detectionMat.rows; i++)
        {
            float confidence = detectionMat.at(i, 2);
            if (confidence > confidence_threshold)
            {
                size_t objIndex = (size_t)(detectionMat.at(i, 1));
                float t1_x = detectionMat.at(i, 3) * frame.cols;
                float t1_y = detectionMat.at(i, 4) * frame.rows;
                float br_x = detectionMat.at(i, 5) * frame.cols;
                float br_y = detectionMat.at(i, 6) * frame.rows;

                Rect object_box((int)t1_x, (int)t1_y, (int)(br_x - t1_x), (int)(br_y - t1_y));
                rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
                putText(frame, format("%s", classNames[objIndex]), Point(t1_x, t1_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
            }
        }
        imshow("ssd-video-demo", frame);
        char c = waitKey(50);
        if (c == 27)//按下ESC键
        {
            break;
        }
    }
    capture.release();
    waitKey(0);
    return 0;
}

P130-P131 FCN全卷积神经网络图像分割

(1) CSDN FCN全卷积神经网络图像分割代码:成功,效果极好***

#include
#include
#include

using namespace cv;
using namespace cv::dnn;
using namespace std;

const size_t width = 300;
const size_t height = 300;
String labelFile = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/pascal-classes.txt";
String modelFile = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.caffemodel";
String model_text_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.txt";

vector readColors();
int main(int argc, char** argv) {
    Mat frame = imread("C:/Users/25503/Desktop/9999.jpg");
    if (frame.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", frame);
    resize(frame, frame, Size(500, 500));//改变尺寸
    vector colors = readColors();
    //
        // init net  初始化网络
    Net net = readNetFromCaffe(model_text_file, modelFile);
    Mat blobImage = blobFromImage(frame);

    // use net   使用网络
    float time = getTickCount();
    net.setInput(blobImage, "data");
    Mat score = net.forward("score");
    float tt = getTickCount() - time;
    printf("time consume: %.2f ms \n", (tt / getTickFrequency()) * 1000);

    // segmentation and display   分割并显示
    const int rows = score.size[2];
    const int cols = score.size[3];
    const int chns = score.size[1];
    Mat maxCl(rows, cols, CV_8UC1);
    Mat maxVal(rows, cols, CV_32FC1);

    // setup LUT  LUT查找
    for (int c = 0; c < chns; c++) {
        for (int row = 0; row < rows; row++) {
            const float *ptrScore = score.ptr(0, c, row);
            uchar *ptrMaxCl = maxCl.ptr(row);
            float *ptrMaxVal = maxVal.ptr(row);
            for (int col = 0; col < cols; col++) {
                if (ptrScore[col] > ptrMaxVal[col]) {
                    ptrMaxVal[col] = ptrScore[col];
                    ptrMaxCl[col] = (uchar)c;
                }
            }
        }
    }

    // look up colors 找到对应颜色
    Mat result = Mat::zeros(rows, cols, CV_8UC3);
    for (int row = 0; row < rows; row++) {
        const uchar *ptrMaxCl = maxCl.ptr(row);
        Vec3b *ptrColor = result.ptr(row);
        for (int col = 0; col < cols; col++) {
            ptrColor[col] = colors[ptrMaxCl[col]];
        }
    }
    Mat dst;
    imshow("FCN-demo1", result);
    addWeighted(frame, 0.3, result, 0.7, 0, dst);//增加宽度
    imshow("FCN-demo", dst);

    waitKey(0);
    return 0;
}

vector readColors() {
    vector colors;
    ifstream fp(labelFile);
    if (!fp.is_open()) {
        printf("could not open the file...\n");
        exit(-1);
    }
    string line;
    while (!fp.eof()) {
        getline(fp, line);
        if (line.length()) {
            stringstream ss(line);
            string name;
            ss >> name;
            int temp;
            Vec3b color;
            ss >> temp;
            color[0] = (uchar)temp;
            ss >> temp;
            color[1] = (uchar)temp;
            ss >> temp;
            color[2] = (uchar)temp;
            colors.push_back(color);
        }
    }
    return colors;
}

(2) 教学视频上的 FCN全卷积神经网络图像分割代码:图像分割效果极好*****

#include
#include
#include

using namespace cv;
using namespace std;
using namespace cv::dnn;

const size_t width = 500;
const size_t height = 500;//定义图像文件宽高

vector labels_color();

string label_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/pascal-classes.txt";
string deploy_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.txt";
string model_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.caffemodel";

int main(int argc, char **argv)
{
    Mat src = imread("C:/Users/25503/Desktop/9999.jpg");

    if (!src.data)
    {
        cout << "图像文件未找到!!!" << endl;
        return -1;
    }
    resize(src, src, Size(500, 500), 0, 0);
    vectorcolors = labels_color();
    Net net;
    net = readNetFromCaffe(deploy_file, model_file);//读取二进制文件和描述文件
    float t1 = getTickCount();
    Mat inputblob = blobFromImage(src);
    net.setInput(inputblob, "data");
    Mat score = net.forward("score");
    float t2 = getTickCount();
    float t = (t2 - t1) / getTickFrequency();
    cout << "运行时间:" << t << endl;

    const int rows = score.size[2];   //图像的高
    const int cols = score.size[3];   //图像的宽
    const int chns = score.size[1];   //图像的通道数
    Mat maxCl(rows, cols, CV_8UC1);
    Mat maxVal(rows, cols, CV_32FC1);

    for (int c = 0; c < chns; c++) {
        for (int row = 0; row < rows; row++) {
            const float *ptrScore = score.ptr(0, c, row);
            uchar *ptrMaxCl = maxCl.ptr(row);
            float *ptrMaxVal = maxVal.ptr(row);
            for (int col = 0; col < cols; col++) {
                if (ptrScore[col] > ptrMaxVal[col]) {
                    ptrMaxVal[col] = ptrScore[col];
                    ptrMaxCl[col] = (uchar)c;
                }
            }
        }
    }

    // look up colors
    Mat result = Mat::zeros(rows, cols, CV_8UC3);
    for (int row = 0; row < rows; row++) {
        const uchar *ptrMaxCl = maxCl.ptr(row);
        Vec3b *ptrColor = result.ptr(row);
        for (int col = 0; col < cols; col++) {
            ptrColor[col] = colors[ptrMaxCl[col]];
        }
    }
    Mat dst;
    addWeighted(src, 0.3, result, 0.7, 0, dst);  //图像合并
    imshow("FCN-demo", dst);

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

}

vector labels_color()
{
    vectorcolors;


    ifstream fp(label_file);//打开输入流,读入文件
    if (!fp.is_open())
    {
        printf("文件读入失败!!!\n");
        exit(-1);//直接退出

    }
    string names;
    int temp;
    Vec3b color;
    string line;//标签文件中都有对应的名字
    while (!fp.eof())//当文件没有读到结尾
    {
        getline(fp, line);//读取每一行
        stringstream ss(line); //分割字符串
        ss >> names; //读的第一个字符串是names
        ss >> temp;
        color[0] = temp;  //读一个字符串就给color
        ss >> temp;
        color[1] = temp;
        ss >> temp;
        color[2] = temp;
        colors.push_back(color);

    }
    return colors;
}

你可能感兴趣的

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号