OpenCV之图像处理case(一) 图像摆正与切边

代码

#include "../common/common.hpp"

static Mat src, gray, dst;
static int threshold_value = 100;
static int max_level = 255;
static const char* title = "Contours Result";
static const char* roi_win = "Final Result";

static void findROI(int, void*);
static void m_rotate();

void main(int argc, char** argv)
{
    src = imread(getCVImagesPath("images/case3-1r.png"));
    imshow("src3-1", src);
    m_rotate();

    namedWindow(title, CV_WINDOW_AUTOSIZE);
    createTrackbar("Threshold:", title, &threshold_value, max_level, findROI);
    findROI(0, 0);

    waitKey(0);
}

void findROI(int, void*) // 发现感兴趣区域,即最大外接矩形,然后截取该区域图像显示
{
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Mat canny;
    Canny(gray, canny, threshold_value, threshold_value * 2, 3, false);

    vector<vector<Point>> contours;
    vector<Vec4i> hireachy;
    findContours(canny, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    cout << "contours.size=" << contours.size() << endl;

    float radio = 0.5; // 0.75
    int minW = src.cols*radio; // 最大外接矩形的宽高最小值
    int minH = src.rows*radio;
    RNG rng(12345);
    Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
    Rect bbox;
    for (size_t i = 0; i < contours.size(); i++)
    {
        RotatedRect minRect = minAreaRect(contours[i]); // 得到轮廓最小的矩形,旋转的
        float degree = abs(minRect.angle); // 旋转的角度
        // 此算法不是特别准确,可以优化,只是懒了。。
        if (minRect.size.width>minW && minRect.size.height>minH && minRect.size.width<src.cols-5) // 轮廓所在矩形大于最小宽高
        {
            Point2f pts[4];
            minRect.points(pts);
            bbox = minRect.boundingRect(); // 获取轮廓所在的最小矩形在图像中的位置
            cout << i << ".degree=" << degree << ", width=" << bbox.width << ", height=" << bbox.height << ", x=" << bbox.x << ", y=" << bbox.y << endl;
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            for (size_t i = 0; i < 4; i++)
            {
                line(drawImg, pts[i], pts[(i + 1) % 4], color, 1, 8, 0);
            }
        }
    }
    imshow(title, drawImg);

    if (bbox.width>0 && bbox.height>0)
    {
        Mat roiImg = src(bbox); // ()运算符重载,在图像src上截取rect所在区域的部分
        imshow(roi_win, roiImg);
    }
}

void m_rotate() // 旋转图像,摆正
{
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Mat canny;
    Canny(gray, canny, threshold_value, threshold_value * 2, 3, false);

    vector<vector<Point>> contours;
    vector<Vec4i> hireachy;
    findContours(canny, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    cout << "m_rotate contours.size=" << contours.size() << endl;

    Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
    float maxW = 0;
    float maxH = 0;
    double degree = 0;
    for (size_t i = 0; i < contours.size(); i++)
    {
        RotatedRect minRect = minAreaRect(contours[i]); // 得到轮廓最小的矩形,旋转的
        degree = abs(minRect.angle); // 旋转的角度
        if (degree > 0)
        {
            maxW = max(maxW, minRect.size.width); // 获取最大矩形的宽高
            maxH = max(maxH, minRect.size.height);
        }
    }
    RNG rng(12345);
    for (size_t i = 0; i < contours.size(); i++)
    {
        RotatedRect minRect = minAreaRect(contours[i]); // 得到轮廓最小的矩形,旋转的
        if (maxW==minRect.size.width && maxH==minRect.size.height)
        {
            degree = minRect.angle;
            Point2f pts[4];
            minRect.points(pts);
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
            for (size_t i = 0; i < 4; i++)
            {
                line(drawImg, pts[i], pts[(i + 1) % 4], color, 1, 8, 0);
            }
        }
    }
    cout << "maxW=" << maxW << ", maxH=" << maxH << ", degree=" << degree << endl;
    imshow("drawImg", drawImg);

    Point2f center(src.cols / 2, src.rows / 2); // 旋转图像时的锚点
    Mat rotm = getRotationMatrix2D(center, degree, 1.0); // 根据角度锚点获取旋转矩阵
    // rotm depth=6, type=6, cols=3, rows=2   CV_64F 单通道
    cout << "rotm depth=" << rotm.depth() << ", type=" << rotm.type() << ", cols=" << rotm.cols << ", rows=" << rotm.rows << endl;
    /*
        0.707107, -0.707107, 387.414,
        0.707107, 0.707107, -159.301,
    */
    for (int row = 0; row < rotm.rows; row++)
    {
        for (int col = 0; col < rotm.cols; col++)
        {
            cout << rotm.at<double>(row, col) << ", ";
        }
        cout << endl;
    }
    Mat dst;
    // INTER_LINEAR 表示双线性插值生成旋转后的图像,Scalar(0) 表示旋转后的非输入图像的部分用该颜色填充
    warpAffine(src, dst, rotm, src.size(), INTER_LINEAR, 0, Scalar(0)); // 旋转图像,旋转后的图像的宽高深度通道数与输入图像一致
    imshow("Correct Image", dst);
    dst.copyTo(src);
}

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81318022