更新除穿孔算法,优化填充穿孔不全的问题,BUG-711
This commit is contained in:
parent
6fc4df0550
commit
57082a9efe
|
@ -1,10 +1,5 @@
|
||||||
#include "ImageApplyOutHole.h"
|
#include "ImageApplyOutHole.h"
|
||||||
#include "ImageProcess_Public.h"
|
#include "ImageProcess_Public.h"
|
||||||
//#include <QDebug>
|
|
||||||
|
|
||||||
#ifdef LOG
|
|
||||||
#include "Device/filetools.h"
|
|
||||||
#endif // LOG
|
|
||||||
|
|
||||||
//#define DRAW_PIC
|
//#define DRAW_PIC
|
||||||
|
|
||||||
|
@ -50,10 +45,8 @@ void CImageApplyOutHole::dilateContour(std::vector<cv::Point>& contour, int dist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MIN_CONTOUR_SIZE 10
|
|
||||||
#define RESIZE_FIXED_WIDTH 2448.0
|
#define RESIZE_FIXED_WIDTH 2448.0
|
||||||
#define LINE_WIDTH 18
|
#define LINE_WIDTH 18
|
||||||
#define DILATE_SIZE 16
|
|
||||||
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
#ifdef LOG
|
#ifdef LOG
|
||||||
|
@ -119,22 +112,6 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_CCOMP);
|
hg::findContours(back_thre.clone(), contours_back, b1_back, cv::RETR_CCOMP);
|
||||||
|
|
||||||
////提取正反面图像最大轮廓
|
////提取正反面图像最大轮廓
|
||||||
//for (size_t i = 0; i < contours_front.size(); i++)
|
|
||||||
// if (contours_front[i].size() < MIN_CONTOUR_SIZE)
|
|
||||||
// {
|
|
||||||
// contours_front.erase(contours_front.begin() + i);
|
|
||||||
// b1_front.erase(b1_front.begin() + i);
|
|
||||||
// i--;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//for (size_t i = 0; i < contours_back.size(); i++)
|
|
||||||
// if (contours_back[i].size() < MIN_CONTOUR_SIZE)
|
|
||||||
// {
|
|
||||||
// contours_back.erase(contours_back.begin() + i);
|
|
||||||
// b1_back.erase(b1_back.begin() + i);
|
|
||||||
// i--;
|
|
||||||
// }
|
|
||||||
|
|
||||||
std::vector<cv::Point> maxContour_front = hg::getMaxContour(contours_front, b1_front);
|
std::vector<cv::Point> maxContour_front = hg::getMaxContour(contours_front, b1_front);
|
||||||
std::vector<cv::Point> maxContour_back = hg::getMaxContour(contours_back, b1_back);
|
std::vector<cv::Point> maxContour_back = hg::getMaxContour(contours_back, b1_back);
|
||||||
|
|
||||||
|
@ -184,10 +161,6 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
cv::imwrite("mask3.jpg", mask);
|
cv::imwrite("mask3.jpg", mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//膨胀算法,增大孔洞连通区域面积
|
|
||||||
//element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(DILATE_SIZE * resize_scale, DILATE_SIZE * resize_scale));
|
|
||||||
//cv::dilate(mask, mask, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar(255));
|
|
||||||
|
|
||||||
#ifdef DRAW_PIC
|
#ifdef DRAW_PIC
|
||||||
cv::imwrite("mask4.jpg", mask);
|
cv::imwrite("mask4.jpg", mask);
|
||||||
#endif
|
#endif
|
||||||
|
@ -204,7 +177,9 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
for (size_t j = 0; j < hole_contours[i].size(); j++)
|
||||||
hole_contours[i][j] /= resize_scale;
|
hole_contours[i][j] /= resize_scale;
|
||||||
|
|
||||||
cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area());
|
cv::Mat thumbnail;
|
||||||
|
cv::resize(front(roi_front), thumbnail, cv::Size(200, 200));
|
||||||
|
cv::Scalar color = hg::getBackGroundColor(thumbnail, cv::Mat(), m_threshold);
|
||||||
roi_front.x /= resize_scale;
|
roi_front.x /= resize_scale;
|
||||||
roi_front.y /= resize_scale;
|
roi_front.y /= resize_scale;
|
||||||
roi_front.width /= resize_scale;
|
roi_front.width /= resize_scale;
|
||||||
|
@ -222,7 +197,9 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
{
|
{
|
||||||
int width_ = roi_back.width;
|
int width_ = roi_back.width;
|
||||||
roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转
|
roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转
|
||||||
color = getBackGroudColor(back(roi_back), rrect_back.size.area());
|
|
||||||
|
cv::resize(back(roi_back), thumbnail, cv::Size(200, 200));
|
||||||
|
color = hg::getBackGroundColor(thumbnail, cv::Mat(), m_threshold);
|
||||||
roi_back.x /= resize_scale;
|
roi_back.x /= resize_scale;
|
||||||
roi_back.y /= resize_scale;
|
roi_back.y /= resize_scale;
|
||||||
roi_back.width /= resize_scale;
|
roi_back.width /= resize_scale;
|
||||||
|
@ -240,7 +217,7 @@ void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<cv::Point>> contours_temp;
|
std::vector<std::vector<cv::Point>> contours_temp;
|
||||||
dilateContour(hole_contour, 5);
|
dilateContour(hole_contour, m_borderSize / 4);
|
||||||
contours_temp.push_back(hole_contour);
|
contours_temp.push_back(hole_contour);
|
||||||
cv::Mat back_temp = mats[1](roi_back);
|
cv::Mat back_temp = mats[1](roi_back);
|
||||||
hg::fillPolys(back_temp, contours_temp, color);
|
hg::fillPolys(back_temp, contours_temp, color);
|
||||||
|
@ -379,80 +356,3 @@ std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<s
|
||||||
}
|
}
|
||||||
return hole_contours;
|
return hole_contours;
|
||||||
}
|
}
|
||||||
|
|
||||||
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints)
|
|
||||||
{
|
|
||||||
if (pixelPoints.empty()) return cv::Scalar(255, 255, 255);
|
|
||||||
|
|
||||||
int channels = image.channels();
|
|
||||||
|
|
||||||
int temp[3] = { 0 };
|
|
||||||
for (size_t i = 0, length = pixelPoints.size(); i < length; ++i)
|
|
||||||
{
|
|
||||||
int x = cv::min(cv::max(0, pixelPoints[i].x), image.cols - 1);
|
|
||||||
int y = cv::min(cv::max(0, pixelPoints[i].y), image.rows - 1);
|
|
||||||
|
|
||||||
const unsigned char* ptr = image.ptr(y, x);
|
|
||||||
for (int j = 0; j < channels; ++j)
|
|
||||||
temp[j] += ptr[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
return cv::Scalar(temp[0] / static_cast<int>(pixelPoints.size()),
|
|
||||||
temp[1] / static_cast<int>(pixelPoints.size()),
|
|
||||||
temp[2] / static_cast<int>(pixelPoints.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cv::Scalar CImageApplyOutHole::getBackGroudColor(const cv::Mat& image, int total)
|
|
||||||
{
|
|
||||||
if (image.channels() == 3)
|
|
||||||
{
|
|
||||||
cv::Mat image_bgr[3];
|
|
||||||
cv::split(image, image_bgr);
|
|
||||||
|
|
||||||
uchar bgr[3];
|
|
||||||
for (size_t i = 0; i < 3; i++)
|
|
||||||
bgr[i] = getBackGroudChannelMean(image_bgr[i], total);
|
|
||||||
return cv::Scalar(bgr[0], bgr[1], bgr[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return cv::Scalar::all(getBackGroudChannelMean(image, total));
|
|
||||||
}
|
|
||||||
|
|
||||||
uchar CImageApplyOutHole::getBackGroudChannelMean(const cv::Mat& gray, int total)
|
|
||||||
{
|
|
||||||
cv::Mat image_clone;
|
|
||||||
cv::resize(gray, image_clone, cv::Size(), 0.25, 0.25);
|
|
||||||
|
|
||||||
int threnshold = total / 32;
|
|
||||||
int channels[] = { 0 };
|
|
||||||
int nHistSize[] = { 256 };
|
|
||||||
float range[] = { 0, 256 };
|
|
||||||
const float* fHistRanges[] = { range };
|
|
||||||
cv::Mat hist;
|
|
||||||
cv::calcHist(&image_clone, 1, channels, cv::Mat(), hist, 1, nHistSize, fHistRanges, true, false);
|
|
||||||
|
|
||||||
int hist_array[256];
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
hist_array[i] = hist.at<float>(i, 0);
|
|
||||||
|
|
||||||
int length = 1;
|
|
||||||
const int length_max = 255;
|
|
||||||
while (length < length_max)
|
|
||||||
{
|
|
||||||
for (size_t i = 1; i < 256 - length; i++)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
uint pixSum = 0;
|
|
||||||
for (size_t j = 0; j < length; j++)
|
|
||||||
{
|
|
||||||
count += hist_array[j + i];
|
|
||||||
pixSum += hist_array[j + i] * (i + j);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count >= threnshold)
|
|
||||||
return pixSum / count;
|
|
||||||
}
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
return 255;
|
|
||||||
}
|
|
|
@ -4,31 +4,32 @@
|
||||||
* 功能:装订孔填充
|
* 功能:装订孔填充
|
||||||
* 作者:刘丁维
|
* 作者:刘丁维
|
||||||
* 生成时间:2020/11/21
|
* 生成时间:2020/11/21
|
||||||
* 最近修改时间:2020/05/12 v1.0
|
* 最近修改时间:v1.0 2020/05/12
|
||||||
* 2020/11/17 v1.1
|
* v1.1 2020/11/17
|
||||||
* 2021/09/06 v1.2 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。
|
* v1.2 2021/09/06 调整默认二值化阈值,从原来的50调整为100。将填充颜色从局部颜色提取改为全局颜色提取。
|
||||||
* 2021/11/03 v1.3 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。
|
* v1.3 2021/11/03 增加逻辑,如果正反面图像尺寸差异超过10个像素,直接返回,不再进行除穿孔处理。
|
||||||
* 2021/11/04 v1.4 增加背景抗噪机制,能够抗5像素的背景噪声。
|
* v1.4 2021/11/04 增加背景抗噪机制,能够抗5像素的背景噪声。
|
||||||
* 2021/11/17 v1.5 调整代码格式,避免一些由于opencv版本导致的BUG。
|
* v1.5 2021/11/17 调整代码格式,避免一些由于opencv版本导致的BUG。
|
||||||
* 2022/04/18 v1.6 修复由于图像超出边界导致的定位孔洞异常的BUG。
|
* v1.6 2022/04/18 修复由于图像超出边界导致的定位孔洞异常的BUG。
|
||||||
* 2022/05/04 v1.6.1 增加逻辑判断,如果出现黑图,直接返回,不对原图进行任何处理。
|
* v1.6.1 2022/05/04 增加逻辑判断,如果出现黑图,直接返回,不对原图进行任何处理。
|
||||||
* 2022/07/16 v1.6.2 修复自动识别填充颜色的BUG
|
* v1.6.2 2022/07/16 修复自动识别填充颜色的BUG
|
||||||
* 2022/07/18 v1.6.3 修复mask的一些逻辑错误
|
* v1.6.3 2022/07/18 修复mask的一些逻辑错误
|
||||||
* 2022/07/18 v1.7 修复逻辑BUG,替换构造函数borderSize逻辑,由原来面积改为边长,定义穿孔范围为[borderSize, borderSize * 6]
|
* v1.7 2022/07/18 修复逻辑BUG,替换构造函数borderSize逻辑,由原来面积改为边长,定义穿孔范围为[borderSize, borderSize * 6]
|
||||||
* 2022/07/22 v1.7.1 修复自动识别填充颜色的BUG
|
* v1.7.1 2022/07/22 修复自动识别填充颜色的BUG
|
||||||
* 2022/08/02 v1.7.2 调整部分默认参数以及参数命名
|
* v1.7.2 2022/08/02 调整部分默认参数以及参数命名
|
||||||
* 2022/09/07 v1.8 去掉上下左右边缘范围的统一比例,取而代之是分别设置上下左右的边缘比例
|
* v1.8 2022/09/07 去掉上下左右边缘范围的统一比例,取而代之是分别设置上下左右的边缘比例
|
||||||
* 2022/09/09 v1.8.1 修复边缘定位的精确BUG。
|
* v1.8.1 2022/09/09 修复边缘定位的精确BUG。
|
||||||
* 2022/09/15 v1.8.2 修复一些逻辑BUG。
|
* v1.8.2 2022/09/15 修复一些逻辑BUG。
|
||||||
* 2022/09/15 v1.8.3 提高抗背景噪声能力。
|
* v1.8.3 2022/09/15 提高抗背景噪声能力。
|
||||||
* 2022/09/15 v1.8.4 修复导致崩溃的BUG
|
* v1.8.4 2022/09/15 修复导致崩溃的BUG
|
||||||
* 2022/09/16 v1.9 优化内存消耗
|
* v1.9 2022/09/16 优化内存消耗
|
||||||
* 2022/09/16 v1.9.1 修复缩放比例的逻辑错误。
|
* v1.9.1 2022/09/16 修复缩放比例的逻辑错误。
|
||||||
* 2022/11/17 v1.9.2 修复寻找孔洞轮廓BUG。
|
* v1.9.2 2022/11/17 修复寻找孔洞轮廓BUG。
|
||||||
* 2023/05/16 v1.9.3 修复提取纸张最大轮廓的逻辑BUG。
|
* v1.9.3 2023/05/16 修复提取纸张最大轮廓的逻辑BUG。
|
||||||
* 2023/11/18 v1.10 替换形态学膨胀孔洞轮廓,改为特征矩阵膨胀轮廓说
|
* v1.10 2023/11/18 替换形态学膨胀孔洞轮廓,改为特征矩阵膨胀轮廓说。
|
||||||
* 2023/11/28 v1.10.1 形态学kSize根据borderSize调整
|
* v1.10.1 2023/11/28 形态学kSize根据borderSize调整。
|
||||||
* 版本号:v1.10.1
|
* v1.11 2023/12/02 替换文稿底色提取方案;修复部分孔洞填充不完全的问题。
|
||||||
|
* 版本号:v1.11
|
||||||
|
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
@ -77,12 +78,6 @@ private:
|
||||||
std::vector<std::vector<cv::Point> > filterPoly(std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& m, cv::RotatedRect roi,
|
std::vector<std::vector<cv::Point> > filterPoly(std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& m, cv::RotatedRect roi,
|
||||||
cv::Vec4f edgeScale, float sideLengthLow);
|
cv::Vec4f edgeScale, float sideLengthLow);
|
||||||
|
|
||||||
cv::Scalar getBackGroudColor(const cv::Mat& image, const std::vector<cv::Point> pixelPoints);
|
|
||||||
|
|
||||||
cv::Scalar getBackGroudColor(const cv::Mat& image, int total);
|
|
||||||
|
|
||||||
uchar getBackGroudChannelMean(const cv::Mat& gray, int total);
|
|
||||||
|
|
||||||
void dilateContour(std::vector<cv::Point>& contour, int distance);
|
void dilateContour(std::vector<cv::Point>& contour, int distance);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue