C++ OpenCV踏面缺陷检测

实现需求

检测出缺陷位置,用矩形框框出,将结果写入xml文件中(voc格式)

将所有矩形框信息写入XML文件

// 将一个矩形框信息写入XML文件
void writeRectangle(std::ofstream& file, const Rectangle& rect) {
    file << "\t<object>" << std::endl;
    file << "\t\t<name>rectangle</name>" << std::endl;
    file << "\t\t<pose>Unspecified</pose>" << std::endl;
    file << "\t\t<truncated>0</truncated>" << std::endl;
    file << "\t\t<difficult>0</difficult>" << std::endl;
    file << "\t\t<bndbox>" << std::endl;
    file << "\t\t\t<xmin>" << rect.x << "</xmin>" << std::endl;
    file << "\t\t\t<ymin>" << rect.y << "</ymin>" << std::endl;
    file << "\t\t\t<xmax>" << rect.w << "</xmax>" << std::endl;
    file << "\t\t\t<ymax>" << rect.h << "</ymax>" << std::endl;
    file << "\t\t</bndbox>" << std::endl;
    file << "\t</object>" << std::endl;
}

// 将所有矩形框信息写入XML文件
void writeXML(const std::string& filename, const std::string& folder, const std::string& imageFileName, const std::vector<cv::Rect>& rectangles) {
    std::ofstream file;
    file.open(filename, std::ios::app);

    file << "<annotation>" << std::endl;
    file << "\t<folder>" << folder << "</folder>" << std::endl;
    file << "\t<filename>" << imageFileName << "</filename>" << std::endl;

    file << "\t<source>" << std::endl;
    file << "\t\t<database>Unknown</database>" << std::endl;
    file << "\t</source>" << std::endl;

    file << "\t<size>" << std::endl;
    file << "\t\t<width>0</width>" << std::endl;
    file << "\t\t<height>0</height>" << std::endl;
    file << "\t\t<depth>3</depth>" << std::endl;
    file << "\t</size>" << std::endl;

    file << "\t<segmented>0</segmented>" << std::endl;

    // 将所有OpenCV矩形框转换为自定义的矩形框结构体
    std::vector<Rectangle> customRectangles;
    for (const cv::Rect& rect : rectangles) {
        customRectangles.push_back({ rect.x, rect.y, rect.width, rect.height });
    }

    // 写入所有矩形框信息
    for (const Rectangle& rect : customRectangles) {
        writeRectangle(file, rect);
    }

    file << "</annotation>" << std::endl;

    file.close();
}

均值滤波差分->二值化->连通域->计算轮廓面积->返回坐标

int main(int argc, char** argv)
{
    Mat dst = imread("..\\img\\test.jpg");
    if (dst.empty()) {
        printf("could not load iamge...\n");
        return -1;
    }
    string filename = "annotation.xml";
    string folder = "images";
    string imageFileName = "test.jpg";

    //均值滤波做差分
    Mat dst_blur, diff, binary, dst_gray;
    cvtColor(dst, dst_gray, COLOR_RGB2GRAY);
    blur(dst_gray, dst_blur, Size(3, 501), Point(-1, -1));
    absdiff(dst_gray, dst_blur, diff);
    //imshow("差分", diff);
    threshold(diff, binary, 70, 255, THRESH_BINARY);
    // adaptiveThreshold(diff, binary, 255, THRESH_BINARY, ADAPTIVE_THRESH_GAUSSIAN_C, 7, 8);
    medianBlur(binary, binary, 3);
    namedWindow("二值化", WINDOW_NORMAL | WINDOW_KEEPRATIO);
    imshow("二值化", binary);
    std::vector<std::vector<cv::Point>>contours;
    std::vector<cv::Rect> rectangles;
    findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());
    for (int i = 0; i < contours.size(); i++)
    {
        int aero = contourArea(contours[i]);                       //计算轮廓面积
        if (aero > 200)
        {
            Rect rect = boundingRect(contours[i]);
            std::vector<cv::Rect> rectangles;
            rectangles.push_back({ rect.tl().x, rect.tl().y, rect.br().x, rect.br().y });
            //绘制轮廓  
            //rect.tl().x, rect.tl().y, rect.br().x, rect.br().y 
            // drawContours(dst, contours, i, Scalar(0, 0, 255), 2); // polygon
            rectangle(dst, rect, Scalar(0, 0, 255), 2);              // 矩形框
            cout << "左上顶点的坐标:" << rect.tl() << "右下顶点的坐标: " << rect.br() << endl;
            writeXML(filename, folder, imageFileName, rectangles);
        }
    }
    namedWindow("close", WINDOW_NORMAL | WINDOW_KEEPRATIO);
    imshow("close", dst);
    waitKey(0);
    //imwrite("./result.jpg", dst);
    return 0;
}

完整代码

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <fstream>
#include <vector>

using namespace cv;
using namespace std;

// 定义一个表示矩形框的结构体
struct Rectangle {
    int x, y, w, h;
};

// 将一个矩形框信息写入XML文件
void writeRectangle(std::ofstream& file, const Rectangle& rect) {
    file << "\t<object>" << std::endl;
    file << "\t\t<name>rectangle</name>" << std::endl;
    file << "\t\t<pose>Unspecified</pose>" << std::endl;
    file << "\t\t<truncated>0</truncated>" << std::endl;
    file << "\t\t<difficult>0</difficult>" << std::endl;
    file << "\t\t<bndbox>" << std::endl;
    file << "\t\t\t<xmin>" << rect.x << "</xmin>" << std::endl;
    file << "\t\t\t<ymin>" << rect.y << "</ymin>" << std::endl;
    file << "\t\t\t<xmax>" << rect.w << "</xmax>" << std::endl;
    file << "\t\t\t<ymax>" << rect.h << "</ymax>" << std::endl;
    file << "\t\t</bndbox>" << std::endl;
    file << "\t</object>" << std::endl;
}

// 将所有矩形框信息写入XML文件
void writeXML(const std::string& filename, const std::string& folder, const std::string& imageFileName, const std::vector<cv::Rect>& rectangles) {
    std::ofstream file;
    file.open(filename, std::ios::app);

    file << "<annotation>" << std::endl;
    file << "\t<folder>" << folder << "</folder>" << std::endl;
    file << "\t<filename>" << imageFileName << "</filename>" << std::endl;

    file << "\t<source>" << std::endl;
    file << "\t\t<database>Unknown</database>" << std::endl;
    file << "\t</source>" << std::endl;

    file << "\t<size>" << std::endl;
    file << "\t\t<width>0</width>" << std::endl;
    file << "\t\t<height>0</height>" << std::endl;
    file << "\t\t<depth>3</depth>" << std::endl;
    file << "\t</size>" << std::endl;

    file << "\t<segmented>0</segmented>" << std::endl;

    // 将所有OpenCV矩形框转换为自定义的矩形框结构体
    std::vector<Rectangle> customRectangles;
    for (const cv::Rect& rect : rectangles) {
        customRectangles.push_back({ rect.x, rect.y, rect.width, rect.height });
    }

    // 写入所有矩形框信息
    for (const Rectangle& rect : customRectangles) {
        writeRectangle(file, rect);
    }

    file << "</annotation>" << std::endl;

    file.close();
}




int main(int argc, char** argv)
{
    Mat dst = imread("..\\img\\test.jpg");
    if (dst.empty()) {
        printf("could not load iamge...\n");
        return -1;
    }
    string filename = "annotation.xml";
    string folder = "images";
    string imageFileName = "test.jpg";

    //均值滤波做差分
    Mat dst_blur, diff, binary, dst_gray;
    cvtColor(dst, dst_gray, COLOR_RGB2GRAY);
    blur(dst_gray, dst_blur, Size(3, 501), Point(-1, -1));
    absdiff(dst_gray, dst_blur, diff);
    //imshow("差分", diff);
    threshold(diff, binary, 70, 255, THRESH_BINARY);
    // adaptiveThreshold(diff, binary, 255, THRESH_BINARY, ADAPTIVE_THRESH_GAUSSIAN_C, 7, 8);
    medianBlur(binary, binary, 3);
    namedWindow("二值化", WINDOW_NORMAL | WINDOW_KEEPRATIO);
    imshow("二值化", binary);
    std::vector<std::vector<cv::Point>>contours;
    std::vector<cv::Rect> rectangles;
    findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE, cv::Point());
    for (int i = 0; i < contours.size(); i++)
    {
        int aero = contourArea(contours[i]);                       //计算轮廓面积
        if (aero > 200)
        {
            Rect rect = boundingRect(contours[i]);
            std::vector<cv::Rect> rectangles;
            rectangles.push_back({ rect.tl().x, rect.tl().y, rect.br().x, rect.br().y });
            //绘制轮廓  
            //rect.tl().x, rect.tl().y, rect.br().x, rect.br().y 
            // drawContours(dst, contours, i, Scalar(0, 0, 255), 2); // polygon
            rectangle(dst, rect, Scalar(0, 0, 255), 2);              // 矩形框
            cout << "左上顶点的坐标:" << rect.tl() << "右下顶点的坐标: " << rect.br() << endl;
            writeXML(filename, folder, imageFileName, rectangles);
        }
    }
    namedWindow("close", WINDOW_NORMAL | WINDOW_KEEPRATIO);
    imshow("close", dst);
    waitKey(0);
    //imwrite("./result.jpg", dst);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值