DryDetect.h
#pragma once
#include <iostream>
#include <io.h>
#include <fstream>
#include <algorithm>
#include "opencv2/opencv.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
struct DryParam
{
cv::Rect DryCard = cv::Rect(1070, 300, 390, 710);
int drydetect = 1;
float resizeRatio = 0;
double thresh1 = 40;
double thresh2 = 255;
int minWidth = 80;
int minHeight = 80;
int maxWidth = 130;
int maxHeight = 130;
float alpha = 2;
float beta = 5;
cv::Vec3b lower_black = cv::Vec3b(26, 14, 24);
cv::Vec3b upper_black = cv::Vec3b(115, 158, 125);
cv::Vec3b lower_black1 = cv::Vec3b(14, 0, 0);
cv::Vec3b upper_black1 = cv::Vec3b(70, 148, 82);
cv::Vec3b lower_black2 = cv::Vec3b(14, 0, 0);
cv::Vec3b upper_black2 = cv::Vec3b(110, 255, 82);
cv::Vec3b lower = cv::Vec3b(43, 18, 134);
cv::Vec3b upper = cv::Vec3b(95, 80, 200);
cv::Vec3b lower_white = cv::Vec3b(0, 0, 130);
cv::Vec3b upper_white = cv::Vec3b(150, 50, 250);
cv::Vec3b lower_blue = cv::Vec3b(90, 133, 42);
cv::Vec3b upper_blue = cv::Vec3b(107, 255, 155);
cv::Vec3b lower_blue2 = cv::Vec3b(65, 113, 30);
cv::Vec3b upper_blue2 = cv::Vec3b(95, 255, 124);
cv::Vec3b lower_green = cv::Vec3b(28, 151, 55);
cv::Vec3b upper_green = cv::Vec3b(40, 255, 145);
cv::Vec3b lower_green2 = cv::Vec3b(54, 74, 75);
cv::Vec3b upper_green2 = cv::Vec3b(71, 145, 140);
};
void PrintCostTime(const char* str, double& t1, double& t2);
void getFiles(string path, vector<string>& files);
bool findSquares(const Mat& image, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
void BrightnessContrast(Mat& src, DryParam& DP);
void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP);
void get_morphology_image(Mat &mask_img);
bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
void sort_boxes(std::vector<cv::Rect>& resultBoxes);
int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
DryDetect.cpp
#include "DryDetect.h"
void PrintCostTime(const char* str, double& t1, double& t2) {
double t = (t2 - t1) * 1000 / cv::getTickFrequency();
printf("%s ===> %.2f ms\n", str, t);
}
void getFiles(string path, vector<string>& files)
{
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
char* files_format[2] = { "\\*.jpg" ,"\\*.png" };
for (int i = 0; i < sizeof(files_format) / sizeof(char*); i++) {
p.assign(path).append(files_format[i]);
hFile = _findfirst(p.c_str(), &fileinfo);
if (hFile != -1)
{
do
{
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
}
else
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
}
bool cmp(cv::Rect a, cv::Rect b)
{
bool big = a.width * a.height > b.width * b.height;
return big;
}
int sort_indexes(std::vector<cv::Rect>& b)
{
std::sort(b.begin(), b.end(), cmp);
return 0;
}
static inline float intersection_area(const cv::Rect& a, const cv::Rect& b)
{
const float eps = 1e-5;
float x1max = max(a.x, b.x);
float x2min = min(a.width + a.x, b.width + b.x);
float y1max = max(a.y, b.y);
float y2min = min(a.height + a.y, b.height + b.y);
float overlapWidth = x2min - x1max;
float overlapHeight = y2min - y1max;
if (overlapHeight > 0 && overlapHeight > 0) {
float inter1 = overlapWidth * overlapHeight;
return inter1;
}
else {
return -1;
}
}
std::vector<cv::Rect> nms_sorted_bboxes(std::vector<cv::Rect>& boxes, float nms_threshold)
{
sort_indexes(boxes);
std::vector<cv::Rect> finalResults;
std::vector<int> keep;
finalResults.clear();
keep.clear();
const int n = boxes.size();
std::vector<float> areas(n);
for (int i = 0; i < n; i++)
{
areas[i] = boxes[i].width * boxes[i].height;
keep.push_back(1);
}
for (int i = 0; i < n; i++)
{
const cv::Rect& a = boxes[i];
if (keep[i]) {
for (int j = i + 1; j < n; j++)
{
const cv::Rect& b = boxes[j];
float inter_area = intersection_area(a, b);
if (inter_area > 0) {
float union_area = areas[i] + areas[j] - inter_area;
if (inter_area / union_area > nms_threshold)
keep[i] = 0;
}
}
}
}
for (int i = 0; i < n; i++)
{
if (keep[i])
{
finalResults.push_back(boxes[i]);
}
}
return finalResults;
}
bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
{
Mat input = _input.clone();
Mat gray, canny, gray2;
BrightnessContrast(input, DP);
cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
Canny(gray, canny, DP.thresh1, DP.thresh2);
Mat kernel = Mat::ones(cv::Size(5, 5), CV_8UC1);
morphologyEx(canny, canny, cv::MORPH_CLOSE, kernel);
std::vector<std::vector<cv::Point>> Contours;
cv::findContours(canny, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
if (int(Contours.size()) == 0) {
return false;
}
for (int i = 0; i < int(Contours.size()); i++)
{
vector<Point> p = Contours[i];
cv::Rect rect = boundingRect(p);
if (rect.width < DP.minWidth || rect.height < DP.minHeight)
{
continue;
}
if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
{
continue;
}
detectBoxes.push_back(rect);
}
return true;
}
bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
{
Mat blur, mask_img;
Mat HSV = Mat(input.size(), CV_8UC3);
cvtColor(input, HSV, COLOR_BGR2HSV);
get_mask_image(HSV, mask_img, DP);
get_morphology_image(mask_img);
std::vector<std::vector<cv::Point>> Contours;
cv::findContours(mask_img, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
if (int(Contours.size()) == 0)
{
return false;
}
for (int i = 0; i < int(Contours.size()); i++)
{
vector<Point> p = Contours[i];
cv::Rect rect = boundingRect(p);
if (rect.width < DP.minWidth || rect.height < DP.minHeight)
{
continue;
}
if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
{
continue;
}
detectBoxes.push_back(rect);
}
return true;
}
bool findSquares(const Mat& _src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
{
std::vector<cv::Rect>detectBoxes;
resultBoxes.clear();
detectBoxes.clear();
Mat image = _src.clone();
Mat blur, gray, dst, canny, hsv, mask;
HSVDet(image, detectBoxes, DP);
CannyDet(image, detectBoxes, DP);
if (int(detectBoxes.size()) == 0) {
return false;
}
resultBoxes = nms_sorted_bboxes(detectBoxes, 0.35);
if (int(resultBoxes.size()) == 8) {
return true;
}
return false;
}
void BrightnessContrast(Mat& src, DryParam& DP)
{
int height = src.rows;
int width = src.cols;
for (int row = 0; row < height; row++) {
uchar *pixel = src.ptr<uchar>(row);
for (int col = 0; col < width; col++) {
if (src.channels() == 3) {
pixel[0] = saturate_cast<uchar>(pixel[0] * DP.alpha + DP.beta);
pixel[1] = saturate_cast<uchar>(pixel[1] * DP.alpha + DP.beta);
pixel[2] = saturate_cast<uchar>(pixel[2] * DP.alpha + DP.beta);
pixel += 3;
}
else if (src.channels() == 1) {
pixel[col] = pixel[col] * DP.alpha + DP.beta;
}
}
}
}
void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP)
{
Mat mask1, mask2, mask3, mask4, mask5, mask6;
cv::inRange(HSV, DP.lower_black2, DP.upper_black2, mask_img);
bitwise_not(mask_img, mask_img);
}
void get_morphology_image(Mat &mask_img)
{
auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
morphologyEx(mask_img, mask_img, cv::MORPH_CLOSE, kernel);
morphologyEx(mask_img, mask_img, cv::MORPH_OPEN, kernel);
}
bool cmp2(cv::Rect a, cv::Rect b)
{
return a.x < b.x;
}
bool cmp3(cv::Rect a, cv::Rect b)
{
return a.y < b.y;
}
void sort_boxes(std::vector<cv::Rect>& boxes)
{
std::vector<cv::Rect> xBoxes, yBoxes;
xBoxes.clear();
yBoxes.clear();
std::sort(boxes.begin(), boxes.end(), cmp2);
xBoxes.insert(xBoxes.end(), boxes.begin(), boxes.begin() + 4);
yBoxes.insert(yBoxes.end(), boxes.begin() + 4, boxes.end());
std::sort(xBoxes.begin(), xBoxes.end(), cmp3);
std::sort(yBoxes.begin(), yBoxes.end(), cmp3);
boxes.clear();
boxes.insert(boxes.end(), xBoxes.begin(), xBoxes.end());
boxes.insert(boxes.end(), yBoxes.begin(), yBoxes.end());
}
int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
{
if (!src.data) {
return -1;
}
Mat input;
Mat img = src.clone();
int col = img.cols;
int row = img.rows;
if (DP.resizeRatio > 0) {
cv::resize(img, input, Size(col * DP.resizeRatio, row * DP.resizeRatio));
}
else {
input = img;
}
if (!findSquares(input, resultBoxes, DP))
{
return 0;
}
sort_boxes(resultBoxes);
for (int i = 0; i < resultBoxes.size(); i++)
{
if (DP.resizeRatio > 0) {
resultBoxes[i].x /= DP.resizeRatio;
resultBoxes[i].y /= DP.resizeRatio;
resultBoxes[i].width /= DP.resizeRatio;
resultBoxes[i].height /= DP.resizeRatio;
}
}
return 1;
}
main.cpp
#include "DryDetect.h"
int main()
{
Mat src = cv::imread("H:\\ImageProcess\\Dry\\image\\7.jpg");
DryParam DP;
DP.minWidth = 80;
DP.minHeight = 80;
DP.maxWidth = 180;
DP.maxHeight = 180;
DP.drydetect = 1;
std::vector<cv::Rect> resultBoxes;
int Dryflag;
if (DP.drydetect = 0)
{
Dryflag = 0;
}
else
{
Dryflag = DryAlg(src, resultBoxes, DP);
}
switch (Dryflag)
{
case -1:
{
cout << "load image error..." << endl;
break;
}
case 0:
{
cout << "detect box fail..." << endl;
break;
}
default:
break;
}
return 0;
}