基于OpenCV实现的极值区域(Extremal Region)提取

一. 极值区域的定义

极值区域(Extremal Region, ER)是指区域外边界的像素值严格大于区域内像素值的区域。

二. 实现思路

  1. 取不同的阈值 θ ,把图像二值化;
  2. 求二值化图像中的连通区域,即为er区域。

三. 代码实现

  • common.h
#ifndef COMMON_H
#define COMMON_H

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

#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

const double M_PI = acos(-1.0);

#endif
  • er.h
#ifndef ER_H
#define ER_H

#include "common.h"

const int dx[] = { 1, -1, 1, -1, 0, 1, 0, -1};
const int dy[] = { 1, -1, -1, 1, 1, 0, -1, 0};

class ER {
public:
    ER();
    double area;
    // double perimeter;
    Rect bounding_rect;
};

void detect_ers(Mat image, vector &ers);
void show_ers(Mat image, vector ers);

#endif
  • er.cpp
#include "er.h"

ER::ER() {
    area = 0;
    // perimeter = 0;
}

bool is_border_point(int x, int y, Mat label_mat) {
    int label = label_mat.at<int>(x, y);
    for (int i = 0; i < 8; ++i) {
        int tmp_x = x + dx[i];
        int tmp_y = y + dy[i];
        if (!(tmp_x >= 0 && tmp_x < label_mat.rows && tmp_y >= 0 && tmp_y < label_mat.cols)) return true;
        int other_label = label_mat.at<int>(tmp_x, tmp_y);
        if (label != other_label) return true;
    }
    return false;
}

void detect_ers_in_binary(Mat binary, vector &ers) {
    Mat label_mat;
    int label_num = connectedComponents(binary, label_mat);

    vector<vector> components(label_num);
    vector<double> area(label_num);
    vector<double> perimeter(label_num);
    for (int i = 0; i < label_mat.rows; ++i) {
        for (int j = 0; j < label_mat.cols; ++j) {
            int label = label_mat.at<int>(i, j);
            area[label] += 1;
            components[label].push_back(Point(j, i));
            /*
            if (is_border_point(i, j, label_mat)) {
                perimeter[label] += 1;
                components[label].push_back(Point(j, i));
            }
            */
        }
    }

    for (int i = 0; i < components.size(); ++i) {
        if (area[i] < 60 || area[i] > 40000) continue;
        ER er;

        er.area = area[i];
        // er.perimeter = perimeter[i];
        er.bounding_rect = boundingRect(components[i]);
        ers.push_back(er);
    }
}

void detect_ers_in_single_channel(Mat image, vector &ers) {
    Mat gray_image;
    cvtColor(image, gray_image, COLOR_BGR2GRAY);

    for (int theta = 0; theta < 256; theta += 10) {
        Mat binary, binary_inv;
        threshold(gray_image, binary, theta, 255, THRESH_BINARY);
        detect_ers_in_binary(binary, ers);

        threshold(gray_image, binary_inv, theta, 255, THRESH_BINARY_INV);
        detect_ers_in_binary(binary_inv, ers);
    }
}

vector filter_ers(vector ers) {
    vector filtered_ers0;
    for (ER er : ers) {
        double w = er.bounding_rect.width;
        double h = er.bounding_rect.height;

        if (w / h > 0.1 && w / h < 10) {
            filtered_ers0.push_back(er);
        }
    }

    vector filtered_ers1;
    for (int i = 0; i < filtered_ers0.size(); ++i) {
        bool flag0 = true;
        for (int j = 0; j < filtered_ers0.size(); ++j) {
            if (i == j) continue;
            Rect a = filtered_ers0[i].bounding_rect;
            Rect b = filtered_ers0[j].bounding_rect;
            Rect inter_rect = a & b;
            Rect union_rect = a | b;
            if (inter_rect.area() >= union_rect.area() * 0.95 && (a.area() < b.area() || (a.area() == b.area() && i > j))) {
                flag0 = false;
                break;
            }
        }
        if (flag0) {
            filtered_ers1.push_back(filtered_ers0[i]);
        }
    }

    return filtered_ers1;
}

void detect_ers(Mat image, vector &ers) {
    vector channels;
    split(image, channels);

    for (Mat channel : channels) {
        detect_ers_in_single_channel(image, ers);
    }

    ers = filter_ers(ers);
}

void show_ers(Mat image, vector ers) {
    for (ER er : ers) {
        rectangle(image, er.bounding_rect, Scalar(255, 0, 0));
    }

    imshow("img", image);
    waitKey();
}
  • main.cpp
#include "er.h"

int main() {
    string img_path = "E:\\ML\\TextRecognize\\data\\cold_paper_pic\\new_cold\\3.png";   
    Mat rgb_img = imread(img_path);
    vector ers;
    detect_ers(rgb_img, ers);
    show_ers(rgb_img, ers);
    return 0;
}

四. 效果

基于OpenCV实现的极值区域(Extremal Region)提取_第1张图片

你可能感兴趣的:(OpenCV,图像处理)