忘记上传除穿孔以及工具类(补上传)

This commit is contained in:
pm 2019-09-04 09:54:32 +08:00
parent aed1f401f9
commit 155ee06586
5 changed files with 476 additions and 0 deletions

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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); //判断是否在纸张内 10-1
double temp2 = pointPolygonTest(vertices_roi2, p, false); //判断是否在边缘区域内 10-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);
}

View File

@ -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);
};

65
hugaotwainds/filetools.h Normal file
View File

@ -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;
};