twain3.0/huagao/ImageProcess/ImageApplyOutHole.cpp

417 lines
14 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ImageApplyOutHole.h"
#include "ImageProcess_Public.h"
//#include <QDebug>
#ifdef LOG
#include "Device/filetools.h"
#endif // LOG
CImageApplyOutHole::CImageApplyOutHole(void)
: CImageApply()
, m_borderSize(20)
, m_edgeScale(0.1f, 0.1f, 0.1f, 0.1f)
, m_threshold(50)
{
}
CImageApplyOutHole::CImageApplyOutHole(float borderSize, cv::Vec4f edgeScale, double threshold)
: CImageApply()
, m_borderSize(borderSize)
, m_edgeScale(edgeScale)
, m_threshold(threshold)
{
}
CImageApplyOutHole::~CImageApplyOutHole(void)
{
}
void CImageApplyOutHole::apply(cv::Mat& pDib, int side)
{
(void)pDib;
(void)side;
}
#define MIN_CONTOUR_SIZE 10
#define RESIZE_FIXED_WIDTH 2448.0
#define LINE_WIDTH 18
#define DILATE_SIZE 16
void CImageApplyOutHole::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
{
#ifdef LOG
FileTools::write_log("imgprc.txt", "enter ImageOutHole apply");
#endif // LOG
if (mats.size() < 2)
{
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
#endif // LOG
return;
}
if (mats[0].empty() || mats[1].empty())
{
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
#endif // LOG
return;
}
double resize_scale = cv::min(RESIZE_FIXED_WIDTH / static_cast<double>(mats[0].cols), 1.0);
//¶þÖµ»¯Õý·´ÃæͼÏñ
cv::Mat front, back;
if (resize_scale != 1.0)
{
cv::resize(mats[0], front, cv::Size(), resize_scale, resize_scale);
cv::resize(mats[1], back, cv::Size(), resize_scale, resize_scale);
}
else
{
front = mats[0];
back = mats[1];
}
cv::Mat front_thre, back_thre;
hg::threshold_Mat(front, front_thre, m_threshold);
hg::threshold_Mat(back, back_thre, m_threshold);
//cv::imwrite("front_thre.jpg", front_thre);
//cv::imwrite("back_thre.jpg", back_thre);
cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(5 * resize_scale, 1));
cv::morphologyEx(front_thre, front_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
cv::morphologyEx(back_thre, back_thre, cv::MORPH_OPEN, element, cv::Point(-1, -1), 1, cv::BORDER_CONSTANT, cv::Scalar::all(0));
//cv::imwrite("front_thre2.jpg", front_thre);
//cv::imwrite("back_thre2.jpg", back_thre);
//·´Ãæ¶þÖµ»¯Í¼Ïñˮƽ·­×ª
cv::flip(back_thre, back_thre, 1); //1:Horizontal
//Õý·´ÃæͼÏñÑ°±ß
std::vector<std::vector<cv::Point>> contours_front, contours_back;
std::vector<cv::Vec4i> b1_front, b1_back;
hg::findContours(front_thre.clone(), contours_front, b1_front, 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_back = hg::getMaxContour(contours_back, b1_back);
if (maxContour_front.empty() || maxContour_back.empty())
return;
cv::RotatedRect rrect_front = hg::getBoundingRect(maxContour_front); //ÌáÈ¡ÕýÃæ×î´óÂÖÀªµÄ×îСÍâ½Ó¾ØÐÎ
cv::RotatedRect rrect_back = hg::getBoundingRect(maxContour_back); //ÌáÈ¡·´Ãæ×î´óÂÖÀªµÄ×îСÍâ½Ó¾ØÐÎ
//Èç¹ûÕý·´ÃæͼÏñ³ß´ç²îÒ쳬¹ý20¸öÏñËØ£¬Ö±½Ó·ÅÆú´¦Àí
if (cv::abs(rrect_front.size.width - rrect_back.size.width) > 20 ||
cv::abs(rrect_front.size.height - rrect_back.size.height) > 20)
return;
//ÌáÈ¡Õý·´ÃæͼÏñÖصþ²¿·ÖÇøÓò
cv::Rect roi_front, roi_back;
cv::RotatedRect mask_rotatedRect;
getRoi(rrect_front, rrect_back, front.size(), back.size(), roi_front, roi_back, mask_rotatedRect);
cv::Mat roiMat_front(front_thre, roi_front); //ÔÚÕýÃæ¶þֵͼÏñÖнØÈ¡Öصþ²¿·Ö
cv::Mat roiMat_back(back_thre, roi_back); //ÔÚ·´Ãæ¶þֵͼÏñÖнØÈ¡Öصþ²¿·Ö
//cv::imwrite("roiMat_front.jpg", roiMat_front);
//cv::imwrite("roiMat_back.jpg", roiMat_back);
//Õý·´Ãæ¶þֵͼÏñ×ö»òÔËË㣬ÕæÕýïοÕÇøÓò±£Áô0£¬ÆäËûµØ·½Ìî³äΪ255
cv::Mat mask;
cv::bitwise_or(roiMat_front, roiMat_back, mask); //»òÔËË㣬Õý·´Ãæ¶þֵͼÏñÖصþ
//cv::imwrite("mask1.jpg", mask);
//¶þֵͼÏñÖصþͼÏñÑÕÉ«È¡·´£¬ÅòÕÍ£¬ÌáÈ¡ÂÖÀª
cv::bitwise_not(mask, mask);
//cv::imwrite("mask2.jpg", mask); //·´É«
//ΪÁ˱ÜÃâ¿×¶´³¹µ×¹á´©Ö½±ß£¬ÈËΪ»æÖÆÖ½ÕÅÂÖÀª£¬È·±£ËùÓп׶´Îª·â±ÕͼÐΣ¬²»»áÓë±³¾°Õ³Á¬
cv::polylines(mask, hg::getVertices(mask_rotatedRect), true, cv::Scalar(0), LINE_WIDTH * resize_scale); //»æÖÆÖ½ÕžØÐαßÔµ
//cv::imwrite("mask3.jpg", mask);
//ÅòÕÍËã·¨£¬Ôö´ó¿×¶´Á¬Í¨ÇøÓòÃæ»ý
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));
//cv::imwrite("mask4.jpg", mask);
//ÌáÈ¡ÖصþͼÏñÂÖÀª
std::vector<std::vector<cv::Point>> contours_mask;
std::vector<cv::Vec4i> b1_mask;
hg::findContours(mask, contours_mask, b1_mask, cv::RETR_TREE);
//¹ýÂ˷ǿ׶´µÄÁªÍ¨ÇøÓò
std::vector<std::vector<cv::Point>> hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, m_edgeScale, m_borderSize * resize_scale);
for (size_t i = 0; i < hole_contours.size(); i++)
for (size_t j = 0; j < hole_contours[i].size(); j++)
hole_contours[i][j] /= resize_scale;
cv::Scalar color = getBackGroudColor(front(roi_front), rrect_front.size.area());
roi_front.x /= resize_scale;
roi_front.y /= resize_scale;
roi_front.width /= resize_scale;
roi_front.height /= resize_scale;
for (size_t i = 0; i < hole_contours.size(); i++)
{
std::vector<std::vector<cv::Point>> contourss_temp;
contourss_temp.push_back(hole_contours[i]);
cv::Mat front_temp = mats[0](roi_front);
hg::fillPolys(front_temp, contourss_temp, color);
}
if (isTwoSide)
{
int width_ = roi_back.width;
roi_back.x = back.cols - roi_back.width - roi_back.x; //ÒòΪ֮ǰ·´ÃæͼÏñ·­×ª£¬ËùÒÔÏÖÔÚROIÒ²Òª½øÐÐÏàÓ¦·­×ª
color = getBackGroudColor(back(roi_back), rrect_back.size.area());
roi_back.x /= resize_scale;
roi_back.y /= resize_scale;
roi_back.width /= resize_scale;
roi_back.height /= resize_scale;
hole_contours.clear();
hole_contours = filterPoly(contours_mask, b1_mask, mask_rotatedRect, cv::Vec4f(m_edgeScale[0], m_edgeScale[1], m_edgeScale[2], m_edgeScale[3]), m_borderSize * resize_scale);
for (size_t i = 0; i < hole_contours.size(); i++)
{
std::vector<cv::Point> hole_contour;
for (size_t j = 0; j < hole_contours[i].size(); j++)
{
hole_contour.push_back(cv::Point(width_ - hole_contours[i][j].x - 1, hole_contours[i][j].y));
hole_contour[j] /= resize_scale;
}
std::vector<std::vector<cv::Point>> contours_temp;
contours_temp.push_back(hole_contour);
cv::Mat back_temp = mats[1](roi_back);
hg::fillPolys(back_temp, contours_temp, color);
}
}
#ifdef LOG
FileTools::write_log("imgprc.txt", "exit ImageOutHole apply");
#endif // LOG
}
void CImageApplyOutHole::getRoi(cv::RotatedRect rrect_front, cv::RotatedRect rrect_back, const cv::Size& srcSize_front, const cv::Size& srcSize_back, cv::Rect& roi_front,
cv::Rect& roi_back, cv::RotatedRect& mask_rotatedRect)
{
cv::Rect roi_front_ = rrect_front.boundingRect();
cv::Rect roi_back_ = rrect_back.boundingRect();
cv::Size meanSize = (roi_front_.size() + roi_back_.size()) / 2;
roi_front_.x += (roi_front_.width - meanSize.width) / 2;
roi_front_.width = meanSize.width;
roi_front_.y += (roi_front_.height - meanSize.height) / 2;
roi_front_.height = meanSize.height;
roi_back_.x += (roi_back_.width - meanSize.width) / 2;
roi_back_.width = meanSize.width;
roi_back_.y += (roi_back_.height - meanSize.height) / 2;
roi_back_.height = meanSize.height;
mask_rotatedRect.angle = (rrect_front.angle + rrect_back.angle) / 2;
mask_rotatedRect.size = (rrect_front.size + rrect_back.size) / 2.0f;
mask_rotatedRect.center = cv::Point2f(roi_front_.size().width + roi_back_.size().width, roi_front_.size().height + roi_back_.size().height) / 4.0f;
roi_front = roi_front_ & cv::Rect(cv::Point(0, 0), srcSize_front);
roi_back = roi_back_ & cv::Rect(cv::Point(0, 0), srcSize_back);
int offset_left_f = roi_front.x - roi_front_.x;
int offset_left_b = roi_back.x - roi_back_.x;
int offset_top_f = roi_front.y - roi_front_.y;
int offset_top_b = roi_back.y - roi_back_.y;
int offset_right_f = roi_front_.br().x - roi_front.br().x;
int offset_right_b = roi_back_.br().x - roi_back.br().x;
int offset_bottom_f = roi_front_.br().y - roi_front.br().y;
int offset_bottom_b = roi_back_.br().y - roi_back.br().y;
if (offset_left_f > offset_left_b)
{
roi_back.x += offset_left_f - offset_left_b;
roi_back.width -= offset_left_f - offset_left_b;
mask_rotatedRect.center.x -= offset_left_f - offset_left_b;
}
else
{
roi_front.x += offset_left_b - offset_left_f;
roi_front.width -= offset_left_b - offset_left_f;
mask_rotatedRect.center.x -= offset_left_b - offset_left_f;
}
if (offset_top_f > offset_top_b)
{
roi_back.y += offset_top_f - offset_top_b;
roi_back.height -= offset_top_f - offset_top_b;
mask_rotatedRect.center.y -= offset_top_f - offset_top_b;
}
else
{
roi_front.y += offset_top_b - offset_top_f;
roi_front.height -= offset_top_b - offset_top_f;
mask_rotatedRect.center.y -= offset_top_b - offset_top_f;
}
if (offset_right_f > offset_right_b)
roi_back.width -= offset_right_f - offset_right_b;
else
roi_front.width -= offset_right_b - offset_right_f;
if (offset_bottom_f > offset_bottom_b)
roi_back.height -= offset_bottom_f - offset_bottom_b;
else
roi_front.height -= offset_bottom_b - offset_bottom_f;
}
#define SIDE_LENGTH_UP_SCALE 6
#define PI 3.14159265359f
std::vector<std::vector<cv::Point>> CImageApplyOutHole::filterPoly(std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Vec4i>& m,
cv::RotatedRect roi, cv::Vec4f edgeScale, float sideLengthLow)
{
cv::RotatedRect roi2(roi.center,
cv::Size2f(roi.size.width * (1 - edgeScale[2] - edgeScale[3]), roi.size.height * (1 - edgeScale[0] - edgeScale[1])),
roi.angle);
cv::Point2f offset_0(roi.size.width * (edgeScale[2] - edgeScale[3]) / 2 + roi.center.x, roi.size.height * (edgeScale[0] - edgeScale[1]) / 2 + roi.center.y);
roi2.center.x = (offset_0.x - roi.center.x) * cos(roi.angle * PI / 180.0f) - (offset_0.y - roi.center.y) * sin(roi2.angle * PI / 180.0f) + roi.center.x;
roi2.center.y = (offset_0.x - roi.center.x) * sin(roi.angle * PI / 180.0f) + (offset_0.y - roi.center.y) * cos(roi2.angle * PI / 180.0f) + roi.center.y;
std::vector<cv::Point> vertices_roi1 = hg::getVertices(roi);
std::vector<cv::Point> vertices_roi2 = hg::getVertices(roi2);
std::vector<std::vector<cv::Point>> hole_contours;
for (size_t i = 0; i < contours.size(); i++)
{
if (m[i][2] != -1)
{
contours.erase(contours.begin() + i);
m.erase(m.begin() + i);
i--;
continue;
}
cv::RotatedRect rrect = hg::getBoundingRect(contours[i]);
if (rrect.size.width < sideLengthLow ||
rrect.size.height < sideLengthLow ||
rrect.size.width > sideLengthLow * SIDE_LENGTH_UP_SCALE ||
rrect.size.height > sideLengthLow * SIDE_LENGTH_UP_SCALE)
{
contours.erase(contours.begin() + i);
m.erase(m.begin() + i);
i--;
continue;
}
bool enabled = true;
for (size_t j = 0, count = contours[i].size(); j < count; j++)
{
cv::Point p(contours[i][j]);
double temp1 = pointPolygonTest(vertices_roi1, p, false); //ÅжÏÊÇ·ñÔÚÖ½ÕÅÄÚ 1£ºÄÚ£»0£ºÉÏ£»-1£ºÍâ
double temp2 = pointPolygonTest(vertices_roi2, p, false); //ÅжÏÊÇ·ñÔÚ±ßÔµÇøÓòÄÚ 1£ºÄÚ£»0£ºÉÏ£»-1£ºÍâ
//Èç¹ûÔÚÖ½ÕÅÍ⣬»òÕß±ßÔµÄÚ£¬ÊÓΪ·Ç¿×¶´
if (temp1 <= 0 || temp2 >= 0)
{
enabled = false;
//qDebug() << rrect.center.x << ":" << rrect.center.y << "::::" << rrect.size.width << " - " << rrect.size.height;
break;
}
}
if (enabled)
hole_contours.push_back(contours[i]);
}
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;
}