忘记上传除穿孔以及工具类(补上传)
This commit is contained in:
parent
aed1f401f9
commit
155ee06586
|
@ -0,0 +1,60 @@
|
|||
#include "StdAfx.h"
|
||||
#include "ImageMultiOutput.h"
|
||||
|
||||
|
||||
ImageMultiOutput::ImageMultiOutput(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageMultiOutput::~ImageMultiOutput(void)
|
||||
{
|
||||
}
|
||||
|
||||
//void ImageMultiOutput::apply(cv::Mat& pDib,int side)
|
||||
//{
|
||||
// //throw std::logic_error("The method or operation is not implemented.");
|
||||
//}
|
||||
|
||||
cv::Mat ImageMultiOutput::GetMultiFilterMat(cv::Mat &src,int channel)
|
||||
{
|
||||
return FilterColor(src,channel);
|
||||
}
|
||||
|
||||
cv::Mat ImageMultiOutput::FilterColor(cv::Mat image,short channel)
|
||||
{
|
||||
cv::Mat dstImage(image.rows,image.cols,CV_8UC1);
|
||||
|
||||
//int pixelSize = image.depth();
|
||||
int channels = image.channels();
|
||||
if(channel > channels -1){
|
||||
return dstImage;
|
||||
}
|
||||
if ( ( channel == 3 ) && ( channels != 4 ) && ( channels != 8 ))
|
||||
{
|
||||
return dstImage;
|
||||
}
|
||||
if ( channels <= 4 )
|
||||
{
|
||||
int srcOffset = image.step - image.cols* channels ;
|
||||
int dstOffset = dstImage.step - dstImage.cols;
|
||||
unsigned char* src = image.data;
|
||||
unsigned char* dst = dstImage.data;
|
||||
src += channel;
|
||||
|
||||
for ( int y = 0; y < image.rows; y++ )
|
||||
{
|
||||
for ( int x = 0; x < image.cols; x++, src += channels , dst++ )
|
||||
{
|
||||
unsigned short pix = *src;
|
||||
if(pix >=130){
|
||||
pix = 255;
|
||||
}
|
||||
*dst = pix;
|
||||
}
|
||||
src += srcOffset;
|
||||
dst += dstOffset;
|
||||
}
|
||||
}
|
||||
return dstImage;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include "ImageApply.h"
|
||||
|
||||
class ImageMultiOutput
|
||||
{
|
||||
public:
|
||||
ImageMultiOutput(void);
|
||||
~ImageMultiOutput(void);
|
||||
|
||||
cv::Mat GetMultiFilterMat(cv::Mat &src,int channel);
|
||||
private:
|
||||
cv::Mat FilterColor(cv::Mat image,short channel);
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,310 @@
|
|||
#include "StdAfx.h"
|
||||
#include "ImageOutHole.h"
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "opencv/cv.h"
|
||||
#include "opencv2/core/core.hpp"
|
||||
|
||||
ImageOutHole::ImageOutHole(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageOutHole::~ImageOutHole(void)
|
||||
{
|
||||
}
|
||||
|
||||
void ImageOutHole::puncture(Mat& front, Mat& back, double threshold, float edgeScale, double areaThreshold)
|
||||
{
|
||||
//二值化正反面图像
|
||||
threshold = min(max(threshold, 1.0), 254.0);
|
||||
Mat front_thre = threshold_mat(front, threshold);
|
||||
Mat back_thre = threshold_mat(back, threshold);
|
||||
|
||||
//反面二值化图像水平翻转
|
||||
flip(back_thre, back_thre, 1); //1:Horizontal
|
||||
|
||||
//正反面图像寻边
|
||||
vector<vector<Point>> contours_front, contours_back;
|
||||
vector<Vec4i> b1_front, b1_back;
|
||||
findContours22(front_thre.clone(), contours_front, b1_front);
|
||||
findContours22(back_thre.clone(), contours_back, b1_back);
|
||||
#if 0
|
||||
imwrite("front_thre.bmp", front_thre);
|
||||
imwrite("back_thre.bmp", back_thre);
|
||||
#endif
|
||||
|
||||
//提取正反面图像最大轮廓
|
||||
vector<Point> maxContour_front = getMaxContour(contours_front, b1_front);
|
||||
vector<Point> maxContour_back = getMaxContour(contours_back, b1_back);
|
||||
|
||||
RotatedRect rrect_front = minAreaRect(maxContour_front); //提取正面最大轮廓的最小外接矩形
|
||||
RotatedRect rrect_back = minAreaRect(maxContour_back); //提取反面最大轮廓的最小外接矩形
|
||||
|
||||
//提取正反面图像重叠部分区域
|
||||
Rect roi_front, roi_back;
|
||||
RotatedRect mask_rotatedRect;
|
||||
getRoi(rrect_front, rrect_back, Size(front.cols, front.rows), roi_front, roi_back, mask_rotatedRect);
|
||||
Mat roiMat_front(front_thre, roi_front); //在正面二值图像中截取重叠部分
|
||||
Mat roiMat_back(back_thre, roi_back); //在反面二值图像中截取重叠部分
|
||||
|
||||
//正反面二值图像做或运算,真正镂空区域保留0,其他地方填充为255
|
||||
//为了避免孔洞彻底贯穿纸边,认为绘制纸张轮廓,确保所有孔洞为封闭图形,不会与背景粘连。
|
||||
#if 0
|
||||
imwrite("front_thre.bmp", roiMat_front);
|
||||
imwrite("back_thre.bmp", roiMat_back);
|
||||
#endif
|
||||
Mat mask;
|
||||
bitwise_or(roiMat_front, roiMat_back, mask); //或运算,正反面二值图像重叠
|
||||
vector<Point> vertices_point = getVertices(mask_rotatedRect);
|
||||
|
||||
polylines(mask, vertices_point, true, Scalar(255), 3); //绘制纸张矩形边缘
|
||||
|
||||
//二值图像重叠图像颜色取反,并提取轮廓
|
||||
vector<vector<Point>> contours_mask;
|
||||
vector<Vec4i> b1_mask;
|
||||
bitwise_not(mask, mask); //取反
|
||||
findContours22(mask.clone(), contours_mask, b1_mask); //提取重叠图像轮廓
|
||||
|
||||
//过滤非孔洞的联通区域
|
||||
filterPoly(mask, contours_mask, mask_rotatedRect, edgeScale, areaThreshold);
|
||||
|
||||
//膨胀算法,增大孔洞连通区域面积
|
||||
dilate(mask, mask, Mat(), Point(-1, -1), 3, BORDER_DEFAULT, Scalar(255));
|
||||
|
||||
vector<Point> rect_poly;
|
||||
rect_poly.push_back(Point(2, 2));
|
||||
rect_poly.push_back(Point(2, mask.rows - 2));
|
||||
rect_poly.push_back(Point(mask.cols - 2, mask.rows - 2));
|
||||
rect_poly.push_back(Point(mask.cols - 2, 2));
|
||||
polylines(mask, rect_poly, true, Scalar(0), 5); //把mask边缘涂黑
|
||||
|
||||
#if 0
|
||||
imwrite("mask.bmp", mask);
|
||||
#endif
|
||||
//填充正面图像孔洞
|
||||
Mat mask_flip;
|
||||
flip(mask, mask_flip, 1); //因为之前反面图像翻转,所以现在要再翻转回去
|
||||
roi_back.x = back.cols - roi_back.width - roi_back.x; //因为之前反面图像翻转,所以现在ROI也要进行相应翻转
|
||||
fillPuncture(front, mask, roi_front); //正面孔洞填充
|
||||
fillPuncture(back, mask_flip, roi_back); //反面孔洞填充
|
||||
#if 0
|
||||
imwrite("111.jpg", front);
|
||||
imwrite("222.jpg", back);
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat ImageOutHole::threshold_mat(const Mat& src, double threshold)
|
||||
{
|
||||
Mat dst(src.rows, src.cols, CV_8UC1, 1);
|
||||
|
||||
if (src.channels() == 3)
|
||||
{
|
||||
Mat gray;
|
||||
cvtColor(src, gray, COLOR_BGR2GRAY);
|
||||
cv::threshold(gray, dst, threshold, 255, THRESH_BINARY);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::threshold(src, dst, threshold, 255, THRESH_BINARY);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void ImageOutHole::findContours22(const Mat& src, vector<vector<Point>>& contours, vector<Vec4i>& hierarchy,
|
||||
int retr/* = RETR_CCOMP*/, int method/* = CHAIN_APPROX_SIMPLE*/, Point offset /*= Point(0, 0)*/)
|
||||
{
|
||||
CvMat c_image = src;
|
||||
MemStorage storage(cvCreateMemStorage());
|
||||
CvSeq* _ccontours = nullptr;
|
||||
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, method, CvPoint(offset));
|
||||
|
||||
if (!_ccontours)
|
||||
{
|
||||
contours.clear();
|
||||
return;
|
||||
}
|
||||
Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
||||
int total = (int)all_contours.size();
|
||||
contours.resize(total);
|
||||
|
||||
SeqIterator<CvSeq*> it = all_contours.begin();
|
||||
for (int i = 0; i < total; i++, ++it)
|
||||
{
|
||||
CvSeq* c = *it;
|
||||
((CvContour*)c)->color = (int)i;
|
||||
int count = (int)c->total;
|
||||
int* data = new int[count * 2];
|
||||
cvCvtSeqToArray(c, data);
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
contours[i].push_back(Point(data[j * 2], data[j * 2 + 1]));
|
||||
}
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
hierarchy.resize(total);
|
||||
it = all_contours.begin();
|
||||
for (int i = 0; i < total; i++, ++it)
|
||||
{
|
||||
CvSeq* c = *it;
|
||||
int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
|
||||
int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1;
|
||||
int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1;
|
||||
int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1;
|
||||
hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vector<Point> ImageOutHole::getMaxContour(const vector<vector<Point>>& contours, const vector<Vec4i>& hierarchy, int areaThreshold /*= 20000*/)
|
||||
{
|
||||
vector<Point> maxContour;
|
||||
for (size_t i = 0, length = hierarchy.size(); i < length; i++)
|
||||
{
|
||||
Vec4i h = hierarchy[i];
|
||||
if (h[3] == -1)
|
||||
{
|
||||
if (contourArea(contours[i]) > areaThreshold)
|
||||
{
|
||||
maxContour = contours[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxContour;
|
||||
}
|
||||
|
||||
void ImageOutHole::getRoi(RotatedRect rrect_front, RotatedRect rrect_back, Size srcSize, Rect& roi_front, Rect& roi_back, RotatedRect& mask_rotatedRect)
|
||||
{
|
||||
Size size((rrect_front.size.width + rrect_back.size.width) / 2, (rrect_front.size.height + rrect_back.size.height) / 2);
|
||||
float angle = (rrect_front.angle + rrect_back.angle) / 2;
|
||||
|
||||
rrect_front.size = rrect_back.size = size;
|
||||
rrect_front.angle = rrect_back.angle = angle;
|
||||
|
||||
roi_front = rrect_front.boundingRect();
|
||||
roi_back = rrect_back.boundingRect();
|
||||
|
||||
if (roi_front.width!=roi_back.width||roi_front.height!=roi_back.height)
|
||||
{
|
||||
roi_front.height=roi_back.height;
|
||||
roi_front.width=roi_back.width;
|
||||
}
|
||||
|
||||
Point offset(0, 0);
|
||||
int top = min(roi_front.y, roi_back.y);
|
||||
if (top < 0)
|
||||
{
|
||||
roi_front.y -= top;
|
||||
roi_back.y -= top;
|
||||
roi_front.height += top;
|
||||
roi_back.height += top;
|
||||
offset.y += top;
|
||||
}
|
||||
|
||||
int left = min(roi_front.x, roi_back.x);
|
||||
if (left < 0)
|
||||
{
|
||||
roi_front.x -= left;
|
||||
roi_back.x -= left;
|
||||
roi_front.width += left;
|
||||
roi_back.width += left;
|
||||
offset.x += left;
|
||||
}
|
||||
|
||||
int right = max(roi_front.x + roi_front.width, roi_back.x + roi_back.width);
|
||||
if (right >= srcSize.width)
|
||||
{
|
||||
roi_front.width -= (right - srcSize.width + 1);
|
||||
roi_back.width -= (right - srcSize.width + 1);
|
||||
}
|
||||
|
||||
int bottom = max(roi_front.y + roi_front.height, roi_back.y + roi_back.height);
|
||||
if (bottom >= srcSize.height)
|
||||
{
|
||||
roi_front.height -= (bottom - srcSize.height + 1);
|
||||
roi_back.height -= (bottom - srcSize.height + 1);
|
||||
}
|
||||
|
||||
mask_rotatedRect.center = Point((roi_front.width + offset.x) / 2, (roi_front.height + offset.y) / 2);
|
||||
mask_rotatedRect.size = size;
|
||||
mask_rotatedRect.angle = angle;
|
||||
}
|
||||
|
||||
Point ImageOutHole::rotatedPoint(Point p, Point center, double angle)
|
||||
{
|
||||
double cos_ = cos(angle / 180 * CV_PI);
|
||||
double sin_ = sin(angle / 180 * CV_PI);
|
||||
|
||||
double x = (p.x - center.x) * cos_ - (p.y - center.y) * sin_ + center.x;
|
||||
double y = (p.y - center.y) * cos_ + (p.x - center.x) * sin_ + center.y;
|
||||
|
||||
return Point(x, y);
|
||||
}
|
||||
|
||||
vector<Point> ImageOutHole::getVertices(RotatedRect rect)
|
||||
{
|
||||
vector<Point> points;
|
||||
|
||||
Point leftTop(rect.center.x - rect.size.width / 2, rect.center.y - rect.size.height / 2);
|
||||
Point leftBottom(rect.center.x - rect.size.width / 2, rect.center.y + rect.size.height / 2);
|
||||
Point rightTop(rect.center.x + rect.size.width / 2, rect.center.y - rect.size.height / 2);
|
||||
Point rigthBottom(rect.center.x + rect.size.width / 2, rect.center.y + rect.size.height / 2);
|
||||
|
||||
points.push_back(rotatedPoint(leftTop, rect.center, rect.angle));
|
||||
points.push_back(rotatedPoint(leftBottom, rect.center, rect.angle));
|
||||
points.push_back(rotatedPoint(rigthBottom, rect.center, rect.angle));
|
||||
points.push_back(rotatedPoint(rightTop, rect.center, rect.angle));
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
void ImageOutHole::filterPoly(const Mat& mask, vector<vector<Point>>& contours, RotatedRect roi, float edgeScale, double areaThreshold)
|
||||
{
|
||||
edgeScale = min(0.49f, max(edgeScale, 0.0f));
|
||||
RotatedRect roi2(roi.center, Size(roi.size.width * (1 - edgeScale * 2), roi.size.height * (1 - edgeScale * 2)), roi.angle);
|
||||
|
||||
vector<Point> vertices_roi1 = getVertices(roi);
|
||||
vector<Point> vertices_roi2 = getVertices(roi2);
|
||||
|
||||
vector<Point> contour;
|
||||
for (size_t i = 0, length = contours.size(); i < length; i++)
|
||||
{
|
||||
//contour = /*Mat_<Point>*/(contours[i]);
|
||||
if (contourArea(contours[i]) < areaThreshold)
|
||||
{
|
||||
fillConvexPoly(mask, contours[i], Scalar(0));
|
||||
continue;
|
||||
}
|
||||
for (int j = 0, count = contours[i].size(); j < count; j++)
|
||||
{
|
||||
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:外
|
||||
//如果在纸张外,或者边缘内,视为非孔洞,填充为0
|
||||
if (temp1 < 0 || temp2 > 0)
|
||||
{
|
||||
fillConvexPoly(mask, contours[i], Scalar(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageOutHole::fillPuncture(Mat& src, const Mat& mask, Rect roi)
|
||||
{
|
||||
Mat mask_temp;
|
||||
if (src.channels() == 3)
|
||||
{
|
||||
cvtColor(mask, mask_temp, COLOR_GRAY2RGB);
|
||||
}
|
||||
else
|
||||
{
|
||||
mask_temp = mask;
|
||||
}
|
||||
Mat src_roi(src, roi);
|
||||
bitwise_or(src_roi, mask_temp, src_roi);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "ImageApply.h"
|
||||
#include <vector>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
using namespace cv;
|
||||
|
||||
class ImageOutHole
|
||||
{
|
||||
public:
|
||||
ImageOutHole(void);
|
||||
~ImageOutHole(void);
|
||||
public:
|
||||
void puncture(Mat& front, Mat& back, double threshold, float edgeScale, double areaThreshold);
|
||||
private:
|
||||
cv::Mat threshold_mat(const Mat& src, double threshold);
|
||||
void findContours22(const Mat& src, vector<vector<Point>>& contours, vector<Vec4i>& hierarchy, int retr = RETR_CCOMP, int method = CHAIN_APPROX_SIMPLE, Point offset = Point(0, 0));
|
||||
vector<Point> getMaxContour(const vector<vector<Point>>& contours, const vector<Vec4i>& hierarchy, int areaThreshold = 20000);
|
||||
void getRoi(RotatedRect rrect_front, RotatedRect rrect_back, Size srcSize, Rect& roi_front, Rect& roi_back, RotatedRect& mask_rotatedRect);
|
||||
Point rotatedPoint(Point p, Point center, double angle);
|
||||
vector<Point> getVertices(RotatedRect rect);
|
||||
void filterPoly(const Mat& mask, vector<vector<Point>>& contours, RotatedRect roi, float edgeScale, double areaThreshold);
|
||||
void fillPuncture(Mat& src, const Mat& mask, Rect roi);
|
||||
};
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
#include <io.h>
|
||||
#include <fstream>
|
||||
|
||||
class FileTools
|
||||
{
|
||||
public:
|
||||
static std::vector<std::string> getFiles(std::string path)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
getFiles(path, files);
|
||||
return files;
|
||||
}
|
||||
|
||||
static void write_log(std::string filepath, std::string log)
|
||||
{
|
||||
std::ofstream ofs(filepath, std::ios::app);
|
||||
ofs << log << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
static void getFiles(std::string path, std::vector<std::string>& files)
|
||||
{
|
||||
//文件句柄
|
||||
long hFile = 0;
|
||||
//文件信息
|
||||
struct _finddata_t fileinfo;
|
||||
std::string p;
|
||||
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo))!=-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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
StopWatch() { valEnd = valStart = clock(); }
|
||||
void start() { valStart = clock(); }
|
||||
void stop() { valEnd =clock(); }
|
||||
double time_run() { return (double)(valEnd - valStart)/CLOCKS_PER_SEC; }
|
||||
|
||||
private:
|
||||
clock_t valStart;
|
||||
clock_t valEnd;
|
||||
};
|
||||
|
Loading…
Reference in New Issue