0.基类
algobase.h
#ifndef ALGOBASE_H
#define ALGOBASE_H
#include "algorithms_global.h"
#include <opencv2/opencv.hpp>
class ALGORITHMS_EXPORT QkAlgoBase {
public:
QkAlgoBase(cv::Mat src, std::vector<cv::RotatedRect> rois,
std::vector<cv::RotatedRect> masks);
virtual ~QkAlgoBase() {};
virtual void operator()() = 0;
protected:
cv::Mat m_srcImg {}; // 原始图像
cv::Mat m_maskImg {};
std::vector<cv::RotatedRect> m_rois {}; // 需要划分的roi区域
std::vector<cv::RotatedRect> m_masks {};// 需要打掩膜的地方
};
#endif // ALGOBASE_H
algobase.cpp
#include "algobase.h"
QkAlgoBase::QkAlgoBase(cv::Mat src, std::vector<cv::RotatedRect> rois, std::vector<cv::RotatedRect> masks)
: m_srcImg(src)
, m_rois(rois)
, m_masks(masks)
{
}
1.单ROI区域均值算子
任意选择一个ROI区域(矩形框,矩形框任意角度),里面含有带任意角度的矩形框掩膜,计算ROI区域内不带掩膜区域的均值,并且设置一个上下限,如果均值在上下限内则认为通过,否则则认为不通过。
mean.h
#ifndef MEAN_H
#define MEAN_H
#include "algobase.h"
#include "algorithms_global.h"
#define RUN_TEST_CODE
class ALGORITHMS_EXPORT QkMean : public QkAlgoBase {
public:
QkMean(cv::Mat src, cv::RotatedRect rois,
std::vector<cv::RotatedRect> masks = std::vector<cv::RotatedRect> {});
~QkMean();
void setParams(float refVal, float lowerPer, float upperPer); // 参考值,上下限
void setParams(float lowerVal, float upperVal); // 上限值,下限值
virtual void operator()() override;
float getMeanValue() { return m_meanValue; } // 平均值
bool getResult() { return m_isOK; } // 确定是否ok
private:
cv::Mat makeMaskImg();
float calcuMean();
bool judge();
void fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color);
private:
struct Params;
Params* m_params {};
float m_meanValue { -1.0 };
bool m_isOK { false };
};
struct QkMean::Params {
float upperLimitVal {};
float lowerLimitVal {};
};
#endif // MEAN_H
mean.cpp
#include "mean.h"
#include <QDebug>
QkMean::QkMean(cv::Mat src, cv::RotatedRect rois, std::vector<cv::RotatedRect> masks)
: QkAlgoBase(src, std::vector<cv::RotatedRect> { rois }, masks)
, m_params(new Params)
{
if (m_srcImg.channels() != 1)
throw std::invalid_argument("QkMean operator demand a grey-scale input image");
}
QkMean::~QkMean()
{
delete m_params;
}
void QkMean::setParams(float refVal, float lowerPer, float upperPer)
{
if (!(refVal > 0 && lowerPer > 0 && upperPer > 0))
throw std::invalid_argument("QkMean::setParams(float refVal, float lowerPer, float upperPer) demands"
" refVal > 0 && lowerPer > 0 && upperPer > 0");
m_params->lowerLimitVal = refVal * (1.0 - lowerPer / 100.0);
m_params->upperLimitVal = refVal * (1.0 + upperPer / 100.0);
}
void QkMean::setParams(float lowerVal, float upperVal)
{
if (!(upperVal >= lowerVal))
throw std::invalid_argument("QkMean::setParams(float lowerVal, float upperVal) demands"
" upperVal >= lowerVal");
m_params->lowerLimitVal = lowerVal;
m_params->upperLimitVal = upperVal;
}
void QkMean::operator()()
{
m_maskImg = makeMaskImg();
m_meanValue = calcuMean();
m_isOK = judge();
#ifdef RUN_TEST_CODE
cv::namedWindow("srcImage", cv::WindowFlags::WINDOW_NORMAL);
cv::imshow("srcImage", m_srcImg);
cv::namedWindow("mask", cv::WindowFlags::WINDOW_NORMAL);
cv::imshow("mask", m_maskImg);
cv::waitKey(3000);
#endif
//return m_isOK;
}
cv::Mat QkMean::makeMaskImg()
{
cv::Mat mask(m_srcImg.rows, m_srcImg.cols, CV_8UC1, cv::Scalar::all(0));
fillRotatedRect(mask, m_rois[0], cv::Scalar::all(255));
if (m_masks.empty())
return mask;
for (auto& rrect : m_masks) {
fillRotatedRect(mask, rrect, cv::Scalar::all(0));
}
return mask;
}
float QkMean::calcuMean()
{
return cv::mean(m_srcImg, m_maskImg)[0];
}
bool QkMean::judge()
{
//[lowerLimitVal,upperLimitVal]
return m_meanValue >= m_params->lowerLimitVal && m_meanValue <= m_params->upperLimitVal;
}
void QkMean::fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color)
{
cv::Point2f vertices2f[4];
rrect.points(vertices2f);
cv::Point vertices[4];
for (int i = 0; i < 4; ++i) {
vertices[i] = vertices2f[i];
}
cv::fillConvexPoly(inOutImg, vertices, 4, color);
}
2.多ROI区域均值算子
选择多个ROI区域(矩形框,矩形框任意角度),里面含有带任意角度的矩形框掩膜,计算每个ROI区域内不带掩膜区域的均值,并且设置一个上下限,如果均值在上下限内则认为通过,否则则认为不通过。
mean_extra.h
#ifndef MEAN_EXTRA_H
#define MEAN_EXTRA_H
#include <opencv2/opencv.hpp>
#include <vector>
#include "algobase.h"
#include "mean.h"
#define RUN_TEST_CODE
class ALGORITHMS_EXPORT QkMeanExtra : public QkAlgoBase
{
public:
QkMeanExtra(cv::Mat src, std::vector<cv::RotatedRect> rois,
std::vector<cv::RotatedRect> masks);
~QkMeanExtra();
void setParams(float refVal, float lowerPer, float upperPer,float setper);
void setParams(float lowerVal, float upperVal, float setper);
void operator()() ;
std::vector<float> getMeanValue() { return m_meanValue; }
std::vector<bool> getResult() { return m_isOK; }
bool average_pass_per(); // 均值通过占比
bool average_differ(); // 均值差值
void judge_min_max(); // 均值极值
private:
std::vector<cv::Mat>makeMaskImg();
std::vector<float>calcuMean();
std::vector<bool>judge();
float calcu_max_roi();
float calcu_min_roi();
void fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color);
private:
struct Params;
Params* m_params {};
float max_aver; // 最大平均值
float min_aver; // 最小平均值
std::vector<cv::Mat> m_mulmaskImg; // 多张打掩膜的图像
std::vector<float> m_meanValue; // 平均值
std::vector<bool> m_isOK; // 判断是否Ok
};
struct QkMeanExtra::Params {
float upperLimitVal {};
float lowerLimitVal {};
float m_setper; // 预值
};
#endif // MEAN_EXTRA_H
mean_extra.cpp
# include "mean_extra.h"
# include "mean.h"
// 构造函数
QkMeanExtra::QkMeanExtra(cv::Mat src, std::vector<cv::RotatedRect> rois,
std::vector<cv::RotatedRect> masks)
: QkAlgoBase(src,rois,masks)
, m_params(new Params)
{
if(m_srcImg.channels() != 1)
throw std::invalid_argument("QkMean operator demand a grey-scale input image");
}
// 析构函数
QkMeanExtra::~QkMeanExtra()
{
delete m_params;
}
// 设置参数
void QkMeanExtra::setParams(float refVal, float lowerPer, float upperPer, float setper)
{
if (!(refVal > 0 && lowerPer > 0 && upperPer > 0))
throw std::invalid_argument("QkMean::setParams(float refVal, float lowerPer, float upperPer) demands"
" refVal > 0 && lowerPer > 0 && upperPer > 0");
m_params->lowerLimitVal = refVal * (1.0 - lowerPer / 100.0);
m_params->upperLimitVal = refVal * (1.0 + upperPer / 100.0);
m_params->m_setper = setper;
}
void QkMeanExtra::setParams(float lowerVal, float upperVal, float setper)
{
if (!(upperVal >= lowerVal))
throw std::invalid_argument("QkMean::setParams(float lowerVal, float upperVal) demands"
" upperVal >= lowerVal");
m_params->lowerLimitVal = lowerVal;
m_params->upperLimitVal = upperVal;
m_params->m_setper = setper;
}
void QkMeanExtra::operator()()
{
m_mulmaskImg = makeMaskImg();
m_meanValue = calcuMean();
m_isOK = judge();
max_aver = calcu_max_roi();
min_aver = calcu_min_roi();
//return m_isOK;
}
// 打掩膜的判别矩阵
std::vector<cv::Mat>QkMeanExtra::makeMaskImg()
{
std::vector<cv::Mat> MaskImg;
for(auto& rois : m_rois){
cv::Mat mask(m_srcImg.rows, m_srcImg.cols, CV_8UC1, cv::Scalar::all(0));
fillRotatedRect(mask, rois, cv::Scalar::all(255));
if(m_masks.empty())
MaskImg.push_back(mask);
for(auto& rrect : m_masks){
fillRotatedRect(mask, rrect, cv::Scalar::all(0));
}
MaskImg.push_back(mask);
}
return MaskImg;
}
// 计算各个roi的平均值
std::vector<float>QkMeanExtra::calcuMean()
{
std::vector<float> MeanValue;
for(auto & mulmaskImg : m_mulmaskImg){
MeanValue.push_back(cv::mean(m_srcImg,mulmaskImg)[0]);
}
return MeanValue;
}
// 判别矩阵
std::vector<bool> QkMeanExtra::judge()
{
std::vector<bool> vector_judge;
for(auto& meanValue : m_meanValue){
bool ture_false = meanValue >= m_params->lowerLimitVal && meanValue <= m_params->upperLimitVal;
vector_judge.push_back(ture_false);
}
return vector_judge;
}
// 打掩膜和画取ROI操作
void QkMeanExtra::fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color)
{
cv::Point2f vertices2f[4];
rrect.points(vertices2f);
cv::Point vertices[4];
for(int i = 0; i < 4; ++i){
vertices[i] = vertices2f[i];
}
cv::fillConvexPoly(inOutImg, vertices, 4, color);
}
// 计算roi均值的最大值和最小值
float QkMeanExtra::calcu_max_roi()
{
float max_average = -1;
for(auto& meanValue : m_meanValue){
if(meanValue >= max_average){
max_average = meanValue;
}
}
return max_average;
}
float QkMeanExtra::calcu_min_roi()
{
float min_average = 256;
for(auto& meanValue : m_meanValue){
if(meanValue <= min_average){
min_average = meanValue;
}
}
return min_average;
}
// 均值通过占比
bool QkMeanExtra::average_pass_per()
{
int pass = 0;
int sum = 0;
float pass_average;
for(int i=0; i<m_isOK.size();i++)
{
if(m_isOK[i] !=0){
pass += 1;
}
sum += 1;
}
pass_average = pass/sum;
if(pass_average >= (m_params->m_setper)){
return true;
}
else{
return false;
}
}
// 均值差值
bool QkMeanExtra::average_differ()
{
float minus = max_aver - min_aver;
return (minus >= m_params->lowerLimitVal) && (minus<=m_params->upperLimitVal);
}
// 均值极值
void QkMeanExtra::judge_min_max()
{
if(min_aver >= m_params->lowerLimitVal && min_aver <= m_params->upperLimitVal)
{
std::cout<<"极小值在范围内!"<<std::endl;
}
else{
std::cout<<"极小值不在范围内!"<<std::endl;
}
if(max_aver >= m_params->lowerLimitVal && max_aver <= m_params->upperLimitVal)
{
std::cout<<"极大值在范围内!"<<std::endl;
}
else{
std::cout<<"极大值不在范围内!"<<std::endl;
}
}
3.HS指标判别
将原图RGB转换成为HSV图像,然后设置一个H和S的上下限,选取一个ROI区域(roi区域为矩形框,带任意角度),如果像素在上下限范围内则加入计算,最终输出的是在上下限范围内的像素占总像素的比例。如果这个比例在范围内则通过,否则不通过。
hsjudge.h
#ifndef HSVBASE_H
#define HSVBASE_H
#include <opencv2/opencv.hpp>
#include <vector>
#include "algobase.h"
#define RUN_TEST_CODE
class ALGORITHMS_EXPORT HsJudge : public QkAlgoBase
{
public:
HsJudge(cv::Mat src, cv::RotatedRect rois,
std::vector<cv::RotatedRect> masks = std::vector<cv::RotatedRect> {});
~HsJudge();
void setParams(std::vector<cv::Point>thresholdArea, float lowerPer, float upperPer, int vmin, int vmax);
virtual void operator()() override;
//std::vector<cv::Point> getSelectHS() {return m_params->selectHS;}
std::vector<cv::Point> getMatchPoint() {return matchPoint;}
cv::Mat getModulationCircle() {return modulationCircle;}
float getCalcuPer() {return per;}
float getResult() {return m_isOK;}
private:
cv::Mat makeMaskImg(); // makeMaskImg
std::vector<cv::Point> selectROI(); // the ROI area of srcimg
cv::Mat DrawConvx(); // Draw modulation circle
float calcuPer();
bool judge();
cv::Point convertTomc(int H, int S);
void fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color);
private:
struct Params;
Params* m_params {};
std::vector<cv::Point> matchPoint; // findNonZeros
cv::Mat modulationCircle; // modulation circle
float per; // percentage
bool m_isOK{false};
};
struct HsJudge::Params{
std::vector<cv::Point> selectHS; // ROI area of HSV
float upperLimitPer {};
float lowerLimitPer {};
};
#endif // HSVBASE_H
hsjudge.cpp
#include "hsjudge.h"
#include <QDebug>
HsJudge::HsJudge(cv::Mat src, cv::RotatedRect rois, std::vector<cv::RotatedRect> masks)
: QkAlgoBase(src, std::vector<cv::RotatedRect> { rois }, masks)
{
if(m_srcImg.channels() != 3)
throw std::invalid_argument("QkMean operator demand a grey-scale input image");
}
HsJudge::~HsJudge()
{
delete m_params;
}
void HsJudge::setParams(std::vector<cv::Point>thresholdArea, float lowerPer, float upperPer, int vmin, int vmax)
{
m_params->selectHS = thresholdArea;
m_params->lowerLimitPer = lowerPer;
m_params->upperLimitPer = upperPer;
}
void HsJudge::operator()()
{
m_maskImg = makeMaskImg();
matchPoint = selectROI();
modulationCircle = DrawConvx();
per = calcuPer();
m_isOK = judge();
}
cv::Mat HsJudge::makeMaskImg()
{
cv::Mat mask(m_srcImg.rows, m_srcImg.cols, CV_8UC1, cv::Scalar::all(0));
fillRotatedRect(mask, m_rois[0], cv::Scalar::all(255));
if (m_masks.empty())
return mask;
for (auto& rrect : m_masks) {
fillRotatedRect(mask, rrect, cv::Scalar::all(0));
}
return mask;
}
std::vector<cv::Point> HsJudge::selectROI()
{
std::vector<cv::Point> idx;
cv::findNonZero(m_maskImg,idx);
return idx;
}
cv::Mat HsJudge::DrawConvx()
{
// 绘制区域在调制圆上的情况
// HS为极坐标形式,输入格式为(角度,H的值)
cv::Mat base(511, 511, CV_8UC1, cv::Scalar(150)); // 基底
cv::Point center = cv::Point(255, 255); // 圆心
int radius = 255; // 半径为255
circle(base, center, radius, cv::Scalar(255), -1); // 绘制调制圆
// 将HS极坐标转换为(x,y)
std::vector<cv::Point>convert_HS;
for (auto& m_hs : m_params->selectHS)
{
cv::Point convert;
convert.x = int((m_hs.y * cos(m_hs.x)) + 255);
convert.y = int((m_hs.y * sin(m_hs.x)) + 255);
convert_HS.push_back(convert);
}
fillPoly(base, convert_HS, cv::Scalar(0), 8, 0);
polylines(base, convert_HS, true, cv::Scalar(0), 1, 8, 0);
//namedWindow("调制圆", WINDOW_GUI_NORMAL);
//imshow("调制圆", base);
return base;
}
void HsJudge::fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color)
{
cv::Point2f vertices2f[4];
rrect.points(vertices2f);
cv::Point vertices[4];
for (int i = 0; i < 4; ++i) {
vertices[i] = vertices2f[i];
}
cv::fillConvexPoly(inOutImg, vertices, 4, color);
}
float HsJudge::calcuPer()
{
cv::Mat hsvimage;
cv::cvtColor(m_srcImg, hsvimage, cv::COLOR_BGR2HSV);
int sum = 0; // 像素总和
int match = 0; // 符合条件的像素
for(auto& point : matchPoint)
{
int H = hsvimage.at<cv::Vec3b>(point.x, point.y)[0];
int S = hsvimage.at<cv::Vec3b>(point.x, point.y)[1];
int V = hsvimage.at<cv::Vec3b>(point.x, point.y)[3];
cv::Point mc = convertTomc(H, S); // 转换到调制圆坐标
if (modulationCircle.at<uchar>(mc) == 255) { // 符合的像素
match += 1;
}
sum += 1;
}
float matchPer = match / sum;
return matchPer;
}
bool HsJudge::judge()
{
return ((per >= m_params->lowerLimitPer) && (per <= m_params->upperLimitPer));
}
cv::Point HsJudge::convertTomc(int H, int S)
{
return cv::Point(int(S * cos(H) + 255), int(S * sin(H) + 255));
}
4.HSV指标判别
将原图RGB转换成为HSV图像,然后设置一个H,S和V的上下限,选取一个ROI区域(roi区域为矩形框,带任意角度),如果像素在上下限范围内则加入计算,最终输出的是在上下限范围内的像素占总像素的比例。如果这个比例在范围内则通过,否则不通过。
hsvbase.h
#ifndef HSVBASE_H
#define HSVBASE_H
#include <opencv2/opencv.hpp>
#include <vector>
#include "algobase.h"
#define RUN_TEST_CODE
class ALGORITHMS_EXPORT HsvJudge : public QkAlgoBase
{
public:
HsvJudge(cv::Mat src, cv::RotatedRect rois,
std::vector<cv::RotatedRect> masks = std::vector<cv::RotatedRect> {});
~HsvJudge();
void setParams(std::vector<cv::Point>thresholdArea, float lowerPer, float upperPer, int vmin, int vmax);
virtual void operator()() override;
//std::vector<cv::Point> getSelectHS() {return m_params->selectHS;}
std::vector<cv::Point> getMatchPoint() {return matchPoint;}
cv::Mat getModulationCircle() {return modulationCircle;}
float getCalcuPer() {return per;}
float getResult() {return m_isOK;}
private:
cv::Mat makeMaskImg(); // makeMaskImg
std::vector<cv::Point> selectROI(); // the ROI area of srcimg
cv::Mat DrawConvx(); // Draw modulation circle
float calcuPer();
bool judge();
cv::Point convertTomc(int H, int S);
void fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color);
private:
struct Params;
Params* m_params {};
std::vector<cv::Point> matchPoint; // findNonZeros
cv::Mat modulationCircle; // modulation circle
float per; // percentage
bool m_isOK{false};
};
struct HsvJudge::Params{
std::vector<cv::Point> selectHS; // ROI area of HSV
float upperLimitPer {};
float lowerLimitPer {};
int VMin;
int VMax;
};
#endif // HSVBASE_H
hsvbase.cpp
#include "hsvbase.h"
#include <QDebug>
HsvJudge::HsvJudge(cv::Mat src, cv::RotatedRect rois, std::vector<cv::RotatedRect> masks)
: QkAlgoBase(src, std::vector<cv::RotatedRect> { rois }, masks)
{
if(m_srcImg.channels() != 3)
throw std::invalid_argument("QkMean operator demand a grey-scale input image");
}
HsvJudge::~HsvJudge()
{
delete m_params;
}
void HsvJudge::setParams(std::vector<cv::Point>thresholdArea, float lowerPer, float upperPer, int vmin, int vmax)
{
m_params->selectHS = thresholdArea;
m_params->lowerLimitPer = lowerPer;
m_params->upperLimitPer = upperPer;
m_params->VMin = vmin;
m_params->VMax = vmax;
}
void HsvJudge::operator()()
{
m_maskImg = makeMaskImg();
matchPoint = selectROI();
modulationCircle = DrawConvx();
per = calcuPer();
m_isOK = judge();
}
cv::Mat HsvJudge::makeMaskImg()
{
cv::Mat mask(m_srcImg.rows, m_srcImg.cols, CV_8UC1, cv::Scalar::all(0));
fillRotatedRect(mask, m_rois[0], cv::Scalar::all(255));
if (m_masks.empty())
return mask;
for (auto& rrect : m_masks) {
fillRotatedRect(mask, rrect, cv::Scalar::all(0));
}
return mask;
}
std::vector<cv::Point> HsvJudge::selectROI()
{
std::vector<cv::Point> idx;
cv::findNonZero(m_maskImg,idx);
return idx;
}
cv::Mat HsvJudge::DrawConvx()
{
// 绘制区域在调制圆上的情况
// HS为极坐标形式,输入格式为(角度,H的值)
cv::Mat base(511, 511, CV_8UC1, cv::Scalar(150)); // 基底
cv::Point center = cv::Point(255, 255); // 圆心
int radius = 255; // 半径为255
circle(base, center, radius, cv::Scalar(255), -1); // 绘制调制圆
// 将HS极坐标转换为(x,y)
std::vector<cv::Point>convert_HS;
for (auto& m_hs : m_params->selectHS)
{
cv::Point convert;
convert.x = int((m_hs.y * cos(m_hs.x)) + 255);
convert.y = int((m_hs.y * sin(m_hs.x)) + 255);
convert_HS.push_back(convert);
}
fillPoly(base, convert_HS, cv::Scalar(0), 8, 0);
polylines(base, convert_HS, true, cv::Scalar(0), 1, 8, 0);
//namedWindow("调制圆", WINDOW_GUI_NORMAL);
//imshow("调制圆", base);
return base;
}
void HsvJudge::fillRotatedRect(cv::Mat& inOutImg, cv::RotatedRect rrect, cv::Scalar color)
{
cv::Point2f vertices2f[4];
rrect.points(vertices2f);
cv::Point vertices[4];
for (int i = 0; i < 4; ++i) {
vertices[i] = vertices2f[i];
}
cv::fillConvexPoly(inOutImg, vertices, 4, color);
}
float HsvJudge::calcuPer()
{
cv::Mat hsvimage;
cv::cvtColor(m_srcImg, hsvimage, cv::COLOR_BGR2HSV);
int sum = 0; // 像素总和
int match = 0; // 符合条件的像素
for(auto& point : matchPoint)
{
int H = hsvimage.at<cv::Vec3b>(point.x, point.y)[0];
int S = hsvimage.at<cv::Vec3b>(point.x, point.y)[1];
int V = hsvimage.at<cv::Vec3b>(point.x, point.y)[3];
cv::Point mc = convertTomc(H, S); // 转换到调制圆坐标
if ((modulationCircle.at<uchar>(mc) == 255) &&
(V >= m_params->VMin && V <= m_params->VMax)) { // 符合的像素
match += 1;
}
sum += 1;
}
float matchPer = match / sum;
return matchPer;
}
bool HsvJudge::judge()
{
return ((per >= m_params->lowerLimitPer) && (per <= m_params->upperLimitPer));
}
cv::Point HsvJudge::convertTomc(int H, int S)
{
return cv::Point(int(S * cos(H) + 255), int(S * sin(H) + 255));
}
5.贯穿算法
检查是否有高亮的物体贯穿矩形框的宽度(白色),通常用来检测引脚是否存在桥联。
distribution.h
#ifndef DISTRIBUTION_H
#define DISTRIBUTION_H
#include <opencv2/opencv.hpp>
#include <vector>
#include "algobase.h"
#include "algorithms_global.h"
#define RUN_TEST_CODE
class ALGORITHMS_EXPORT Distribution : public QkAlgoBase{
public:
Distribution(cv::Mat src, cv::RotatedRect rois,
std::vector<cv::RotatedRect> masks = std::vector<cv::RotatedRect> {});
~Distribution();
virtual void operator()() override;
bool final_result() { return result; }
private:
cv::Mat threhold(); // image binaryzation
cv::Mat expand(); // img expand
cv::Mat flood(); // img_flood
bool judge(); // final judge
private:
cv::Mat img_threhold; // image binaryzation
cv::Mat img_expand; // image expansion
cv::Mat img_flood; // Floodfill
bool result; // final result
};
#endif // DISTRIBUTION_H
distribution.cpp
#include "distribution.h"
#include <QDebug>
#include <vector>
Distribution::Distribution(cv::Mat src, cv::RotatedRect rois, std::vector<cv::RotatedRect> masks)
: QkAlgoBase(src, std::vector<cv::RotatedRect> { rois }, masks)
{
if(m_srcImg.channels() != 3)
throw std::invalid_argument("QkMean operator demand a grey-scale input image");
}
Distribution::~Distribution()
{
}
void Distribution::operator()()
{
img_threhold = threhold();
img_expand = expand();
img_flood = flood();
result = judge();
}
cv::Mat Distribution::threhold()
{
cv::Mat src_gray;
cvtColor(m_srcImg, src_gray,cv::COLOR_BGR2GRAY);
cv::Mat src_threshold;
threshold(src_gray, src_threshold, 127, 255, cv::THRESH_OTSU);
return src_threshold;
}
cv::Mat Distribution::expand()
{
cv::Mat dst;
int element_size = 2;
int s = element_size * 2 + 1;
cv::Mat structureElement = getStructuringElement
(cv::MORPH_RECT, cv::Size(s, s), cv::Point(-1, -1));
dilate(img_threhold, dst, structureElement, cv::Point(-1, -1), 1);
return dst;
}
cv::Mat Distribution::flood()
{
int h = img_expand.rows;
int w = img_expand.cols;
cv::Mat dst;
img_expand.copyTo(dst);
std::vector<cv::Point> white;
for (int i = 0; i < 5; i++)
{
for (int row = 0; row < h; row++)
{
if (img_expand.at<uchar>(row, i) == 255)
{
white.push_back(cv::Point(i, row));
}
}
}
std::vector<int> selectPoint;
//设置种子
srand((unsigned)time(NULL));
for (int i = 0; i < 5; i++)
{
selectPoint.push_back(rand() % (white.size()));
floodFill(dst, white[selectPoint[i]], cv::Scalar(127));
}
return dst;
}
bool Distribution::judge()
{
int h = img_flood.rows;
int w = img_flood.cols;
bool result = false;
for (int row = 0; row < h; row++)
{
if (img_flood.at<uchar>(row, w - 1) == 127)
{
result = true;
}
}
return result;
}