Commit 8c1dfa89 张士柳

备份恢复

1 个父辈 3f8a946f
...@@ -257,12 +257,6 @@ static void filterByApriltag(cv::Mat &binary, cv::Mat &labels, std::vector<tMap> ...@@ -257,12 +257,6 @@ static void filterByApriltag(cv::Mat &binary, cv::Mat &labels, std::vector<tMap>
}); });
} }
static inline bool isContainsTwoDCode()
{
return false;
}
static double getThreshVal_Otsu_8u(const cv::Mat& _src) static double getThreshVal_Otsu_8u(const cv::Mat& _src)
{ {
cv::Size size = _src.size(); cv::Size size = _src.size();
...@@ -339,6 +333,62 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src) ...@@ -339,6 +333,62 @@ static double getThreshVal_Otsu_8u(const cv::Mat& _src)
return max_val; return max_val;
} }
static bool decode(std::vector<WaitArea> &waitAreas, cv::Mat &showMat, std::vector<DecodeResult> &strDecodeResults, int iBlockSize, const int iRangeC, double dMinorStep)
{
//全部解码成功
bool allDecode = true;
//进入线程锁
mtx.lock();
//处理解码
for (int i = 0; i < waitAreas.size(); i++)
{
//如果已解码则不需要再次进行解码
//if (waitAreas[i].decode) continue;
//解码结果
std::string strDecodeResult = ""; std::string strDecodeResultType = "QR-Code"; cv::Point ptDecodeResult = cv::Point();
//二值化
cv::Mat binary;
//尝试多种参数解码
for (int blockSize = iBlockSize - 2; blockSize <= iBlockSize + 2; blockSize += 2)
{
for (double d = waitAreas[i].C - (double)iRangeC; d <= waitAreas[i].C + (double)iRangeC; d += dMinorStep)
{
cv::adaptiveThreshold(waitAreas[i].waitArea, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, d);
try {
Ref<LuminanceSource> source = MatSource::create(binary);
Ref<Reader> reader;
reader.reset(new QRCodeReader);
Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
Ref<Result> result(reader->decode(bitmap, DecodeHints(DecodeHints::TRYHARDER_HINT)));
if (!result.empty())
{
//waitAreas[i].decode = true;
strDecodeResult = result->getText()->getText();
goto breakLoop;
}
}
catch (...) {
//there is something wrong
}
}
}
breakLoop:
{
//做标记
if (strDecodeResult != std::string())
{
cv::putText(showMat, strDecodeResult, waitAreas[i].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
strDecodeResults.push_back(DecodeResult(0, waitAreas[i].Pt, strDecodeResult, strDecodeResultType));
}
}
allDecode &= true/*waitAreas[i].decode*/;
}
//离开线程锁
mtx.unlock();
return allDecode;
}
static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> &hints, cv::Mat &showMat, std::vector<DecodeResult> &decodeResults, int iBlockSize, const int iRangeC, double dMinorStep) static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> &hints, cv::Mat &showMat, std::vector<DecodeResult> &decodeResults, int iBlockSize, const int iRangeC, double dMinorStep)
{ {
//进入线程锁 //进入线程锁
...@@ -352,16 +402,16 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -352,16 +402,16 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
//优先当作DM来解码,因为它比较快 //优先当作DM来解码,因为它比较快
if (!waitAreas[i].oneD) if (!waitAreas[i].oneD)
{ {
cv::Mat binary; for (int d = waitAreas[i].C - iRangeC; d <= waitAreas[i].C + 2 * iRangeC; d += (int)dMinorStep)
//尝试多种参数解码
for (double d = waitAreas[i].C - (double)iRangeC; d <= waitAreas[i].C + (double)iRangeC; d += dMinorStep)
{ {
cv::Mat binary;
cv::adaptiveThreshold(waitAreas[i].waitArea, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, iBlockSize, d); cv::adaptiveThreshold(waitAreas[i].waitArea, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, iBlockSize, d);
DmtxMessage *msg; DmtxMessage *msg;
DmtxRegion *reg; DmtxRegion *reg;
DmtxImage *img = NULL; DmtxImage *img = NULL;
if (abs(d) == 0) if (abs(d) < DBL_EPS)
{ {
img = dmtxImageCreate(waitAreas[i].waitArea.data, waitAreas[i].waitArea.cols, waitAreas[i].waitArea.rows, DmtxPack8bppK); img = dmtxImageCreate(waitAreas[i].waitArea.data, waitAreas[i].waitArea.cols, waitAreas[i].waitArea.rows, DmtxPack8bppK);
} }
...@@ -393,7 +443,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -393,7 +443,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
} }
dmtxDecodeDestroy(&dec); dmtxDecodeDestroy(&dec);
dmtxImageDestroy(&img); dmtxImageDestroy(&img);
//解码则结束循环 //
if (bDecode) if (bDecode)
break; break;
} }
...@@ -413,7 +463,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -413,7 +463,7 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
cv::pyrUp(src, src, cv::Size(src.cols * 2, src.rows * 2)); cv::pyrUp(src, src, cv::Size(src.cols * 2, src.rows * 2));
//判断解码结果 //判断解码结果
double threshVal = getThreshVal_Otsu_8u(src); double threshVal = getThreshVal_Otsu_8u(src);
for (double c = threshVal - 8 * iRangeC; c < threshVal + 8 * iRangeC; c += dMinorStep) for (double c = threshVal - 4 * iRangeC; c < threshVal + 4 * iRangeC; c += dMinorStep)
{ {
cv::Mat binary; cv::Mat binary;
cv::threshold(src, binary, c, 255, cv::THRESH_BINARY); cv::threshold(src, binary, c, 255, cv::THRESH_BINARY);
...@@ -494,9 +544,9 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -494,9 +544,9 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
if (std::find(hints.begin(), hints.end(), "QR_CODE") != hints.end()) { if (std::find(hints.begin(), hints.end(), "QR_CODE") != hints.end()) {
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader)); readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader));
} }
//if (std::find(hints.begin(), hints.end(), "DATA_MATRIX") != hints.end()) { if (std::find(hints.begin(), hints.end(), "DATA_MATRIX") != hints.end()) {
// readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader)); readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader));
//} }
if (std::find(hints.begin(), hints.end(), "AZTEC") != hints.end()) { if (std::find(hints.begin(), hints.end(), "AZTEC") != hints.end()) {
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader)); readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader));
} }
...@@ -542,8 +592,51 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -542,8 +592,51 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
} }
} }
} }
//如果仍未解码
if (!bDecode)
{
cv::Mat srcPyrUp;
cv::pyrUp(src, srcPyrUp, cv::Size(src.cols * 2, src.rows * 2));
for (int blockSize = (2 * iBlockSize + 1) - 2; blockSize <= (2 * iBlockSize + 1) + 2; blockSize += 2)
{
for (double d = waitAreas[i].C - (double)iRangeC; d <= waitAreas[i].C + (double)iRangeC; d += dMinorStep)
{
cv::adaptiveThreshold(srcPyrUp, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, d);
try {
//创建图像
Ref<LuminanceSource> source = MatSource::create(binary);
Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
Ref<Result> result(readers_[ii]->decode(bitmap, zxing::DecodeHints::TRYHARDER_HINT));
//如果解码成功
if (!result.empty())
{
ptResult = waitAreas[i].Pt;
strResult = result->getText()->getText();
switch (result->getBarcodeFormat())
{
case AZTEC:
strResultType = "AZTEC";
break;
case DATA_MATRIX:
strResultType = "DATA_MATRIX";
break;
case QR_CODE:
strResultType = "QR_CODE";
break;
default:
break;
}
goto breakLoop;
}
}
catch (...) {
//there is something wrong
}
}
}
}
} }
//解码成功
breakLoop: breakLoop:
{ {
if (strResult != std::string()) if (strResult != std::string())
...@@ -557,57 +650,86 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> ...@@ -557,57 +650,86 @@ static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string>
if (bDecode) if (bDecode)
{ {
decodeResults.push_back(DecodeResult(waitAreas[i].angle, ptResult, strResult, strResultType)); decodeResults.push_back(DecodeResult(waitAreas[i].angle, ptResult, strResult, strResultType));
cv::putText(showMat, strResult, ptResult, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255)); cv::putText(showMat, strResult, ptResult / 2, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
} }
} }
//离开线程锁 //离开线程锁
mtx.unlock(); mtx.unlock();
} }
static int calcHist(cv::Mat src)
{
const int histSize = 256;
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
cv::Mat hist;
cv::calcHist(&src, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
return maxIdx[0];
}
int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown, double dToleErr, double dMinorStep) int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown, double dToleErr, double dMinorStep)
{ {
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage); cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, tpImage.iDepth, tpImage.vpImage);
if (src.empty()) { if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST; return FUNC_IMAGE_NOT_EXIST;
} }
//提取ROI //提取ROI
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight)); src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight));
//真实图像数据与尺寸 //图像原图备份
cv::Mat realSrc = src.clone(); cv::Mat backup = src.clone();
int iRealX = realSrc.cols, iRealY = realSrc.rows, iRealBlockSize = iBlockSize;
//降采样 //降采样
if (dScaleUpAndDown != 1.) if (dScaleUpAndDown != 1.)
cv::pyrDown(src, src, cv::Size(cvRound(src.cols*dScaleUpAndDown), cvRound(src.rows*dScaleUpAndDown))); cv::pyrDown(src, src, cv::Size(cvRound(src.cols*dScaleUpAndDown), cvRound(src.rows*dScaleUpAndDown)));
//用于显示 //用于显示
cv::Mat showMat; cv::Mat showMat;
cv::cvtColor(src, showMat, cv::COLOR_GRAY2BGR); cv::cvtColor(src, showMat, cv::COLOR_GRAY2BGR);
//图像尺寸,可能为缩放后尺寸 //图像尺寸
int iX = src.cols, iY = src.rows; int X = src.cols, Y = src.rows;
//解码结果
std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>();
//测试用 //测试用
if (dScaleUpAndDown != 1.) cv::Mat srcPrev, binary;
{ //高斯滤波去噪
//太小则不考虑缩小窗口尺寸 int ksize = cvRound((iBlockSize + 1)*dScaleUpAndDown) % 2 == 0 ? cvRound((iBlockSize + 1)*dScaleUpAndDown) + 1 : cvRound((iBlockSize + 1)*dScaleUpAndDown);
if (iBlockSize > 3) cv::GaussianBlur(src, srcPrev, cv::Size(ksize, ksize), 0.3);
//条码来说会比背景值小,二维码来说会比背景值大
//计算导数
cv::Mat dx, dy, mag;
cv::Sobel(srcPrev, dx, CV_32F, 1, 0);
cv::Sobel(srcPrev, dy, CV_32F, 0, 1);
//计算梯度幅值
cv::magnitude(dx, dy, mag);
// 归一化
cv::normalize(mag, mag, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(mag, srcPrev);
//二值化
cv::threshold(srcPrev, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//膨胀
cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//计算角点响应
cv::Mat harMap;
cv::cornerHarris(src, harMap, cvRound(iBlockSize*dScaleUpAndDown), 3, 0.04);//对二维码效果比较好
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
//计算背景像素
const int histSize = 256;
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
cv::Mat hist;
cv::calcHist(&harMap, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//m1用于检测一维码;m2用于检测二维码
cv::Mat m1(Y, X, CV_8UC1, cv::Scalar(0)), m2(Y, X, CV_8UC1, cv::Scalar(0));
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{ {
iBlockSize = cvRound((double)(iBlockSize + 1)*dScaleUpAndDown) % 2 == 0 ? cvRound((double)(iBlockSize + 1)*dScaleUpAndDown) - 1 : cvRound((double)(iBlockSize + 1)*dScaleUpAndDown) - 1; for (int x = 0; x < X; x++)
{
if (harMap.ptr<uint8_t>(y)[x] < maxIdx[0])
{
m1.ptr<uint8_t>(y)[x] = 255;
}
else if (harMap.ptr<uint8_t>(y)[x] > maxIdx[0])
{
m2.ptr<uint8_t>(y)[x] = 255;
}
}
} }
} });
//高斯滤波去噪
cv::Mat srcPrev, binary;
//确定识别类型 //确定识别类型
std::vector<std::string> hints_; std::vector<std::string> hints_;
split(ccCodeType, "|", hints_); split(ccCodeType, "|", hints_);
...@@ -626,172 +748,54 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -626,172 +748,54 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//是否添加二维码检测 //是否添加二维码检测
bool addTwoDReader = std::find(hints_.begin(), hints_.end(), "QR_CODE") != hints_.end() || bool addTwoDReader = std::find(hints_.begin(), hints_.end(), "QR_CODE") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "DATA_MATRIX") != hints_.end() || std::find(hints_.begin(), hints_.end(), "DATA_MATRIX") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "AZTEC") != hints_.end() || std::find(hints_.begin(), hints_.end(), "AZTEC") != hints_.end();
std::find(hints_.begin(), hints_.end(), "PDF_417") != hints_.end();
//未设置识别类型 //未设置识别类型
if (!addOneDReader && !addTwoDReader) if (!addOneDReader && !addTwoDReader)
return FUNC_CANNOT_CALC; return FUNC_CANNOT_CALC;
//检测热点图,s1用来检测一维码;s2用来检测二维码(条码来说会比背景值小,二维码来说会比背景值大) //所有解码内容
cv::Mat s1(iY, iX, CV_8UC1, cv::Scalar(0)), s2(iY, iX, CV_8UC1, cv::Scalar(0));
//<//////////////////////通用预处理方式//////////////////////>//
//高斯滤波去噪
cv::GaussianBlur(src, srcPrev, cv::Size(iBlockSize, iBlockSize), 0.85);
//
cv::adaptiveThreshold(srcPrev, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iBlockSize, 2);
////分块处理
//for (int blockY = 0; blockY < iY; blockY += iSymbolMax)
//{
// for (int blockX = 0; blockX < iX; blockX += iSymbolMax)
// {
// //用原图来进行过滤最好
// cv::Mat blockSrc = srcPrev(cv::Range(blockY, cv::min(blockY + iSymbolMax, iY)), cv::Range(blockX, cv::min(blockX + iSymbolMax, iX)));
// cv::threshold(blockSrc, blockSrc, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
// }
//}
//略微处理连接断裂二维码部分
//cv::morphologyEx(binary, binary, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound((double)iBlockSize / 3.), cvRound((double)iBlockSize / 3.))));
//连通域分析
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double maxSize = cv::max(stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]); double minSize = cv::min(stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]); double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]; double dRateA = (double)stats.ptr<int>(i)[cv::CC_STAT_AREA] / ((double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] * (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]);
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < cvRound(15.0*dScaleUpAndDown)) || (maxSize > 35 * iBlockSize) || (maxSize < (double)iBlockSize*(1. - dToleErr)))
{
colors[i] = 0;
}
}
//过滤
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = binary.ptr<uint8_t>(y);
for (int x = 0; x < iX; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//格式化文件名
const int bufSize = 32;
char file[bufSize * 4] = { 0 };
sprintf_s(file, "D:\\ResOut\\%s-Mark.png", ccFileName);
cv::imwrite(file, binary);
return FUNC_OK;
//膨胀区域
cv::Mat binaryEx;
cv::morphologyEx(binary, binaryEx, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize * 2 + 1, iBlockSize * 2 + 1)));
//连通域分析
nccomps = cv::connectedComponentsWithStats(binaryEx, labels, stats, centroids);
cv::parallel_for_(cv::Range(1, nccomps), [&](const cv::Range& rangeTop)->void {
for (int i = rangeTop.start; i < rangeTop.end; i++)
{
cv::Rect rec(stats.ptr<int>(i)[cv::CC_STAT_LEFT], stats.ptr<int>(i)[cv::CC_STAT_TOP], stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]);
if ((cv::min(rec.size().width, rec.size().height) > 5 * iBlockSize) && (rec.area() > 5 * std::pow(iBlockSize, 2)))
{
//角点响应图
cv::Mat harMap;
cv::cornerHarris(src(rec), harMap, iBlockSize, 3, 0.04);
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
// 尺寸
cv::Size sz = rec.size();
// 用于一维码检测
cv::Mat m1 = harMap < calcHist(harMap);
const uchar *s1ptr = m1.data;
uchar *d1ptr = s1.data;
// 叠加图像
cv::parallel_for_(cv::Range(0, sz.height), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++) {
for (int x = 0; x < sz.width; x++) {
d1ptr[(x + rec.x) + (y + rec.y)*iX] += s1ptr[(x)+(y)*sz.width];
}
}
});
// 用于二维码检测,似乎用阈值法干扰比较少
cv::Mat m2 = harMap > calcHist(harMap);
const uchar *s2ptr = m2.data;
uchar *d2ptr = s2.data;
// 叠加图像
cv::parallel_for_(cv::Range(0, sz.height), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++) {
for (int x = 0; x < sz.width; x++) {
d2ptr[(x + rec.x) + (y + rec.y)*iX] += s2ptr[(x)+(y)*sz.width];
}
}
});
}
}
});
//输出解码结果
std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>();
//解码内容
std::vector<DecodeResult> decodeResults; std::vector<DecodeResult> decodeResults;
//待解码区域,区分条码类型来识别 //待解码区域,区分条码类型来识别
std::vector<WaitArea> waitAreas; std::vector<WaitArea> waitAreas;
//判断要增加的识别,从这一步可以进行分开处理
if (addOneDReader) if (addOneDReader)
{ {
//去掉干扰 cv::Mat labels, stats, centroids;
cv::bitwise_and(s1, binaryEx, s1); int nccomps = cv::connectedComponentsWithStats(m1, labels, stats, centroids, 4);
//连通域分析 //过滤连通域面积及长/宽比例不符合的,允许50%误差
nccomps = cv::connectedComponentsWithStats(s1, labels, stats, centroids); std::vector<uchar> colors(nccomps + 1, 0);
std::vector<uchar> colors2(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) { for (int i = 1; i < nccomps; i++) {
colors2[i] = 255; colors[i] = 255;
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iRealBlockSize, 2))) if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize*dScaleUpAndDown, 2) * 5) | (m1.ptr<uint8_t>(cvRound(centroids.ptr<double>(i)[1]))[cvRound(centroids.ptr<double>(i)[0])] == 0))
{ {
colors2[i] = 0; colors[i] = 0;
} }
} }
//过滤 //过滤
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void { cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++) for (int y = range.start; y < range.end; y++)
{ {
uint8_t *ptrRow = s1.ptr<uint8_t>(y); uint8_t *ptrRow = m1.ptr<uint8_t>(y);
for (int x = 0; x < iX; x++) for (int x = 0; x < X; x++)
{ {
int label = labels.ptr<int>(y)[x]; int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps); CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors2[label]; ptrRow[x] = colors[label];
} }
} }
}); });
//后续识别 //用于过滤非条码部分
cv::Mat binFilter;
cv::adaptiveThreshold(backup, binFilter, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, ksize, 5);
//处理断裂一维码
//cv::morphologyEx(m1, m1, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//用于轮廓检测 //用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter; std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(s1, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); findContours(m1, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//初步过滤 for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
for (int i = 0; i < int(contourAll.size()); i++)
{ {
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]); cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
double dRate = (double)cv::max(rect.size.height, rect.size.width) / (double)cv::min(rect.size.height, rect.size.width), rgt = cv::contourArea(contourAll[i]) / rect.size.area();
if ((cv::min(rect.size.height, rect.size.width) > iBlockSize * 2) && (cv::contourArea(contourAll[i]) / rect.size.area()) > 0.35)
{
contourFilter.push_back(contourAll[i]);
}
else
cv::drawContours(s1, contourAll, i, cv::Scalar(0), -1);
}
//按照条形码特征过滤
for (int i = 0; i < static_cast<int>(contourFilter.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourFilter[i]);
//最大宽度限制 //最大宽度限制
double minLen = cv::min(rect.size.height, rect.size.width); double minLen = cv::min(rect.size.height, rect.size.width);
if (minLen < 8.*iBlockSize*(1. + dToleErr)) if (minLen < 8.*iBlockSize*dScaleUpAndDown*(1. + dToleErr))
{ {
//增加比例过滤条件 //增加比例过滤条件
cv::Point2f pts[4]; cv::Point2f pts[4];
...@@ -800,15 +804,15 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -800,15 +804,15 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
cv::Point ptStart, ptEnd, ptMid; cv::Point ptStart, ptEnd, ptMid;
if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2])) if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2]))
{ {
ptStart = cv::Point((pts[0] + pts[3]) / 2.); ptEnd = cv::Point((pts[1] + pts[2]) / 2.); ptStart = cv::Point((pts[0] + pts[3]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[1] + pts[2]) / 2. / dScaleUpAndDown);
} }
else else
{ {
ptStart = cv::Point((pts[0] + pts[1]) / 2.); ptEnd = cv::Point((pts[2] + pts[3]) / 2.); ptStart = cv::Point((pts[0] + pts[1]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[2] + pts[3]) / 2. / dScaleUpAndDown);
} }
ptMid = (ptStart + ptEnd) / 2; ptMid = (ptStart + ptEnd) / 2;
cv::LineIterator it(binary, (ptMid + ptEnd) / 2, (ptMid + ptStart) / 2, 4); cv::LineIterator it(binFilter, (ptMid + ptEnd) / 2, (ptMid + ptStart) / 2, 4);
double dis = cv::norm((ptMid + ptEnd) / 2 - (ptMid + ptStart) / 2); double dis = cv::norm((ptMid + ptEnd) / 2 - (ptMid + ptStart) / 2);
...@@ -818,23 +822,23 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -818,23 +822,23 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
double test_line[2]{ 0 }; double test_line[2]{ 0 };
for (int n = 0; n < it.count; n++, ++it) for (int n = 0; n < it.count; n++, ++it)
{ {
if (s1.ptr<uint8_t>(cvRound(it.pos().y))[cvRound(it.pos().x)] == 0) continue; if (m1.ptr<uint8_t>(cvRound(it.pos().y * dScaleUpAndDown))[cvRound(it.pos().x * dScaleUpAndDown)] == 0) continue;
//统计均匀性 //统计均匀性
uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x]; uint8_t next_pixel = binFilter.ptr<uint8_t>(it.pos().y)[it.pos().x];
test_line[next_pixel % 254]++; test_line[next_pixel % 254]++;
if (next_pixel != future_pixel) if (next_pixel != future_pixel)
{ {
flag++; flag++;
future_pixel = 255 - future_pixel; future_pixel = 255 - future_pixel;
} }
showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0); //showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
} }
//满足比例 //满足比例
double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]); double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flag > cvRound((dis / 4.)*(1. - dToleErr))) if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flag > cvRound((dis / 4.)*(1. - dToleErr)))
{ {
cv::Point2f pt[4]; cv::Point2f pt[4];
cv::Size size(cvRound(cv::max(rect.size.height, rect.size.width) + 4 * iBlockSize / 2.), cvRound(cv::min(rect.size.height, rect.size.width))); cv::Size size(cvRound(cv::max(rect.size.height, rect.size.width) + iBlockSize*dScaleUpAndDown / 4.), cvRound(cv::min(rect.size.height, rect.size.width)));
//获取roi位置 //获取roi位置
double _angle = std::atan2((ptEnd.y - ptStart.y), (ptEnd.x - ptStart.x)); double _angle = std::atan2((ptEnd.y - ptStart.y), (ptEnd.x - ptStart.x));
float b = (float)cos(_angle)*0.5f; float b = (float)cos(_angle)*0.5f;
...@@ -852,16 +856,16 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -852,16 +856,16 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//防止越界 //防止越界
for (int n = 0; n < 4; n++) for (int n = 0; n < 4; n++)
{ {
if (pt[n].x < 0) pt[n].x = 0.f; if (pt[n].x >= iX - 1) pt[n].x = float(iX - 1); if (pt[n].y < 0) pt[n].y = 0.f; if (pt[n].y >= iY - 1) pt[n].y = float(iY - 1); if (pt[n].x < 0) pt[n].x = 0.f; if (pt[n].x >= X - 1) pt[n].x = float(X - 1); if (pt[n].y < 0) pt[n].y = 0.f; if (pt[n].y >= Y - 1) pt[n].y = float(Y - 1);
} }
//用采样的方式提取待解码区域 //用采样的方式提取待解码区域
cv::LineIterator itStHeight(realSrc, pt[0], pt[1], 4); cv::LineIterator itStHeight(backup, pt[0], pt[1], 4);
cv::LineIterator itEdHeight(realSrc, pt[3], pt[2], 4); cv::LineIterator itEdHeight(backup, pt[3], pt[2], 4);
cv::LineIterator itStWidth(realSrc, pt[0], pt[3], 4); cv::LineIterator itStWidth(backup, pt[0], pt[3], 4);
cv::LineIterator itEdWidth(realSrc, pt[1], pt[2], 4); cv::LineIterator itEdWidth(backup, pt[1], pt[2], 4);
struct Track struct Track
{ {
...@@ -887,11 +891,11 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -887,11 +891,11 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
//行 //行
for (int n = 0; n < (int)pairStEd.size(); n += iSamplingStep) for (int n = 0; n < (int)pairStEd.size(); n += iSamplingStep)
{ {
cv::LineIterator it(realSrc, pairStEd[n].PosS, pairStEd[n].PosE, 4); cv::LineIterator it(backup, pairStEd[n].PosS, pairStEd[n].PosE, 4);
for (int nn = 0; nn < it.count; nn++, ++it)//列 for (int nn = 0; nn < it.count; nn++, ++it)//列
{ {
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0); //showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
srcSampling.ptr<uint8_t>(0)[nn] = realSrc.ptr<uint8_t>(it.pos().y)[it.pos().x]; srcSampling.ptr<uint8_t>(0)[nn] = backup.ptr<uint8_t>(it.pos().y)[it.pos().x];
} }
//判断是否为二维码 //判断是否为二维码
cv::Mat testMat; cv::Mat testMat;
...@@ -916,43 +920,46 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -916,43 +920,46 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
{ {
cv::line(showMat, pt[j], pt[(j + 1) % 4], cv::Scalar(0, 255, 255), 1); cv::line(showMat, pt[j], pt[(j + 1) % 4], cv::Scalar(0, 255, 255), 1);
} }
//cv::circle(showMat, pt[0], 2, cv::Scalar(255, 0, 0), -1); cv::circle(showMat, pt[0], 2, cv::Scalar(255, 0, 0), -1);
//cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 0), -1); cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 0), -1);
//cv::circle(showMat, pt[2], 2, cv::Scalar(0, 0, 255), -1); cv::circle(showMat, pt[2], 2, cv::Scalar(0, 0, 255), -1);
waitAreas.push_back(WaitArea(cv::Mat(), ptMid, getThreshVal_Otsu_8u(oneDMats[0]), _angle*180. / PI, true, oneDMats)); waitAreas.push_back(WaitArea(cv::Mat(), ptMid, getThreshVal_Otsu_8u(oneDMats[0]), rect.angle, true, oneDMats));
} }
} }
} }
} }
} }
//添加二维码识别
if (addTwoDReader) if (addTwoDReader)
{ {
//测试用
cv::Mat srcFilter;
cv::adaptiveThreshold(src, srcFilter, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, 43, 2);
//去掉小于15个像素的
cv::morphologyEx(srcFilter, srcFilter, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//断裂处连接在一起 //断裂处连接在一起
cv::morphologyEx(s2, s2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * iBlockSize + 1, 2 * iBlockSize + 1))); cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown), cvRound(iBlockSize*dScaleUpAndDown))));
//去除干扰 //去掉无关区域
cv::bitwise_and(binary, s2, s2); cv::bitwise_and(srcFilter, m2, m2);
//对图像过滤 //对二值图像过滤
cv::Mat labels, stats, centroids; cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(s2, labels, stats, centroids); int nccomps = cv::connectedComponentsWithStats(m2, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差 //过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0); std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) { for (int i = 1; i < nccomps; i++) {
colors[i] = 255; colors[i] = 255;
double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]; double dRateA = (double)stats.ptr<int>(i)[cv::CC_STAT_AREA] / ((double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] * (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]); double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT];
if (!((dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr)) && ((double)stats.ptr<int>(i)[cv::CC_STAT_AREA] > std::pow(20 * 1.414* dScaleUpAndDown, 2)) && \ if ((!(dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))) | (stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr))\
(dRateA >= 0.5*(1. - dToleErr)))) | ((double)stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize / 2, 2) * 15))
{ {
colors[i] = 0; colors[i] = 0;
} }
} }
//第一次过滤 //第一次过滤
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void { cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++) for (int y = range.start; y < range.end; y++)
{ {
uint8_t *ptrRow = s2.ptr<uint8_t>(y); uint8_t *ptrRow = m2.ptr<uint8_t>(y);
for (int x = 0; x < iX; x++) for (int x = 0; x < X; x++)
{ {
int label = labels.ptr<int>(y)[x]; int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps); CV_Assert(0 <= label && label <= nccomps);
...@@ -960,826 +967,269 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -960,826 +967,269 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
} }
} }
}); });
//判断区域内是否包含二维码 //用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter; std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(s2, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); findContours(m2, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++) for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{ {
cv::RotatedRect rec = cv::minAreaRect(contourAll[i]); cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//满足矩形条件与面积条件 //满足矩形条件与面积条件
double dRate = cv::min(rec.size.width, rec.size.height) / cv::max(rec.size.height, rec.size.width); double dRate = cv::min(rect.size.width, rect.size.height) / cv::max(rect.size.height, rect.size.width);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && cv::min(rec.size.width, rec.size.height) > 20) if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && ((double)rect.size.width > double(8. * iBlockSize*dScaleUpAndDown)) && ((double)rect.size.height > double(8. * iBlockSize*dScaleUpAndDown)))
{ {
//范围 contourFilter.push_back(contourAll[i]);
int dynSize = cvRound(cv::max((double)rec.boundingRect().size().height / dScaleUpAndDown, (double)rec.boundingRect().size().width / dScaleUpAndDown));
//用原图来进行过滤最好
cv::Mat waitArea = realSrc(cv::Range(cv::max(0, cvRound(rec.center.y / dScaleUpAndDown) - (2 * iBlockSize + dynSize / 2)), cv::min(iRealY - 1, cvRound(rec.center.y / dScaleUpAndDown) + (2 * iBlockSize + dynSize / 2))), cv::Range(cv::max(0, cvRound(rec.center.x / dScaleUpAndDown) - (2 * iBlockSize + dynSize / 2)), cv::min(iRealX - 1, cvRound(rec.center.x / dScaleUpAndDown) + (2 * iBlockSize + dynSize / 2))));
//测试用
cv::Mat waitAreaEx;
cv::morphologyEx(waitArea, waitAreaEx, cv::MORPH_BLACKHAT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2 * iRealBlockSize + 1, 2 * iRealBlockSize + 1)));
//用对比度阈值过滤
double min, max;
cv::minMaxLoc(waitAreaEx, &min, &max);
if (max - min < 35) {
continue;
}
//计算响应图
cv::Mat harMap;
cv::cornerHarris(waitArea, harMap, iRealBlockSize, 3, 0.04);
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
//进一步判断
cv::Mat m2;
cv::threshold(harMap, m2, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//连接断裂处
cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound((double)iRealBlockSize / 3.), cvRound((double)iRealBlockSize / 3.))));
//用于轮廓检测
std::vector<std::vector<cv::Point>> contours;
findContours(m2, contours, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//最大轮廓
std::vector<cv::Point> contourMax = contours[0];
for (int cc = 0; cc < contours.size(); cc++)
{
if (cv::contourArea(contours[cc]) > cv::contourArea(contourMax))
{
contourMax = contours[cc];
}
}
rec = cv::minAreaRect(contourMax);
dRate = cv::min(rec.size.width, rec.size.height) / cv::max(rec.size.height, rec.size.width);
//判断比例
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && cv::min(rec.size.width, rec.size.height) > 20)
{
double dRateA = std::pow(cv::min(rec.size.height, rec.size.width), 2) / std::pow(dynSize, 2);
if (dRateA >= 0.5*(1. - dToleErr) && ((double)rec.size.width > double(8. * iBlockSize)) && ((double)rec.size.height > double(8. * iBlockSize)))
{
//cv::Point2f pts[4];
//rec.points(pts);
////
//cv::Mat locBinary;
//cv::adaptiveThreshold(waitArea, locBinary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iRealBlockSize, 7);
////扫描线
//cv::Point ptStart, ptEnd;
//ptStart = cv::Point(pts[0]); ptEnd = cv::Point(pts[2]);
////按照比例过滤
//int flags = 0;
//double test_line[2]{ 0 };
//cv::LineIterator it(locBinary, ptStart, ptEnd, 4);
//uint8_t future_pixel = 0;
//for (int n = 0; n < it.count; n++, ++it)
//{
// //统计均匀性
// uint8_t next_pixel = locBinary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// if (next_pixel != future_pixel)
// {
// flags++;
// future_pixel = 255 - future_pixel;
// }
//}
////判断是否满足比例
//double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
//if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flags > 8)
//{
//contourFilter.push_back(contourAll[i]);
//}
//cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
//cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
////外包矩形
//int dynSize = cvRound(cv::max((double)rect.size().height / dScaleUpAndDown, (double)rect.size().width / dScaleUpAndDown));
////疑似二维码区域
//cv::Mat waitArea = realSrc(cv::Range(cv::max(0, cvRound(rRect.center.y / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(realSrc.rows - 1, cvRound(rRect.center.y / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(realSrc.cols - 1, cvRound(rRect.center.x / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize + dynSize / 2))));
////处理后再压入识别
waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rec.center.x / dScaleUpAndDown), cvRound(rec.center.y / dScaleUpAndDown)), 0, 0, false, std::vector<cv::Mat>()));
}
}
} }
} }
for (int i = 0; i < contourFilter.size(); i++)
{
cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
//外包矩形
int dynSize = cvRound(cv::max((double)rect.size().height / dScaleUpAndDown, (double)rect.size().width / dScaleUpAndDown));
//疑似二维码区域
cv::Mat waitArea = backup(cv::Range(cv::max(0, cvRound(rRect.center.y / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(backup.rows - 1, cvRound(rRect.center.y / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(backup.cols - 1, cvRound(rRect.center.x / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)))).clone();
//处理后再压入识别
waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rRect.center.x / dScaleUpAndDown), cvRound(rRect.center.y / dScaleUpAndDown)), 0, 0, false, std::vector<cv::Mat>()));
//画图
cv::rectangle(showMat, rect, cv::Scalar(0, 255, 0), 1);
}
} }
//解码 //解码
//decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, iRangeC, dMinorStep); decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, iRangeC, dMinorStep);
////输出结果 //输出结果
//for (int i = 0; i < decodeResults.size(); i++) for (int i = 0; i < decodeResults.size(); i++)
{
EyemBarCode tpResult;
tpResult.iCenterX = decodeResults[i].ptResult.x;
tpResult.iCenterY = decodeResults[i].ptResult.y;
tpResult.dAngle = decodeResults[i].dAngle;
//分配内容所需内存
tpResult.lpszText = (char *)CoTaskMemAlloc(512);
if (NULL != tpResult.lpszText)
{
char file[512] = { 0 };
sprintf_s(file, "%s", decodeResults[i].strResultText.c_str());
strcpy(tpResult.lpszText, file);
}
else return FUNC_NOT_ENOUGH_MEM;
//分配码型所需内存
tpResult.lpszType = (char *)CoTaskMemAlloc(512);
if (NULL != tpResult.lpszType)
{
char file[512] = { 0 };
sprintf_s(file, "%s", decodeResults[i].strResultType.c_str());
strcpy(tpResult.lpszType, file);
}
else return FUNC_NOT_ENOUGH_MEM;
//添加结果
tpResults->push_back(tpResult);
}
*hResults = tpResults->data();
*ipNum = static_cast<int>(tpResults->size());
*hObject = reinterpret_cast<IntPtr>(tpResults);
////格式化文件名
//const int bufSize = 32;
//char file[bufSize * 4] = { 0 };
//sprintf_s(file, "D:\\ResOut\\%s-Mark.png", ccFileName);
//cv::imwrite(file, showMat);
return FUNC_OK;
////局部二值化
//cv::adaptiveThreshold(src, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iBlockSize, 2);
////去掉大部分干扰项
//binary &= mask;
////对二值图像过滤
//cv::Mat labels, stats, centroids;
//int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids, 4);
////过滤连通域面积及长/宽比例不符合的,允许50%误差
//std::vector<uchar> colors(nccomps + 1, 0);
//for (int i = 1; i < nccomps; i++) {
// colors[i] = 255;
// if ((stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize * 15 * 1.414*(1. + dToleErr))\
// | (false))
// {
// colors[i] = 0;
// }
//}
////第一次过滤
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
////cv::cvtColor(binary, showMat, cv::COLOR_GRAY2BGR);
//const int iScanRadius = 35;
////最好还是用线扫描的方法,具体扫描全图还是按照中心点来扫看时间
////指定长度十字网格遍历是否满足条件黑白比例在1:1,考虑其他方式去扫描,可能速度上会慢一些,如果区分满足各自条件可能会好一些
////,这样可以将其他不必要的过滤掉,最后再合成一张图;2,扫描宽度,根据宽度流来确定是否属于条码、qr、datamatrix,黑白宽度;
////宽度打开都在一个很小变动范围内,允许50%的误差,宽度密度相较目前判断方式可也确定是否是黑白格分布,考虑到一维条码,八个方向只需满足一个方向即可
////这样可以过滤掉一些孤立长条
////vPts[0].Pt = cv::Point(3610, 2433);
//cv::Mat label(Y, X, CV_8UC1, cv::Scalar(0));
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// for (int x = 0; x < X; x++)
// {
// uint8_t future_pixel = binary.ptr<uint8_t>(y)[x];
// if (!future_pixel)
// {
// continue;
// }
// bool iFlag = 0;
// //判断白色像素部分占整条线的比例
// for (double t = -180; t < 180; t += 45)
// {
// float xx = float(x + iScanRadius * cos(t* 0.01745));
// float yy = float(y + iScanRadius * sin(t* 0.01745));
// //防止越界
// if (xx < 0) xx = 0; if (xx >= X - 1) xx = X - 1; if (yy < 0) yy = 0; if (yy >= Y - 1) yy = Y - 1;
// cv::LineIterator it(binary, cv::Point(x, y), cv::Point(cvRound(xx), cvRound(yy)), 4);
// //扫描像素密度,比例接近1:1记录下来
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 0 };
// for (int n = 0; n < it.count; n++, ++it)
// {
// //统计相邻由明到暗个数,并且查看均匀性
// uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (!next_pixel)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// }
// if (cv::max(test_line[0], test_line[1]) <= 0) continue;
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //showMat.at<cv::Vec3b>(cv::Point(x, y)) = cv::Vec3b(0, 255, 0);
// label.ptr<uint8_t>(y)[x] = 255;
// break;
// }
// }
// }
// }
//});
//for (int c = 0; c < (int)vPts.size(); c++)
//{ //{
// EyemBarCode tpResult; // bool iFlag = 0;
// tpResult.iCenterX = decodeResults[i].ptResult.x; // uint8_t future_pixel = binary.ptr<uint8_t>(vPts[c].Pt.y)[vPts[c].Pt.x];
// tpResult.iCenterY = decodeResults[i].ptResult.y; // //判断白色像素部分占整条线的比例
// tpResult.dAngle = decodeResults[i].dAngle; // for (double t = -180; t < 180; t += 45)
// //分配内容所需内存
// tpResult.lpszText = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszText)
// { // {
// char file[512] = { 0 }; // float x = float(vPts[c].Pt.x + iScanRadius * cos(t* 0.01745));
// sprintf_s(file, "%s", decodeResults[i].strResultText.c_str()); // float y = float(vPts[c].Pt.y + iScanRadius * sin(t* 0.01745));
// strcpy(tpResult.lpszText, file);
// //防止越界
// if (x < 0) x = 0; if (x >= X - 1) x = X - 1; if (y < 0) y = 0; if (y >= Y - 1) y = Y - 1;
// cv::LineIterator it(binary, vPts[c].Pt, cv::Point(cvRound(x), cvRound(y)), 4);
// //扫描像素密度,比例接近1:1记录下来
// //测试用
// std::vector<cv::Point> test_point;
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 0 };
// for (int n = 0; n < it.count; n++, ++it)
// {
// //统计相邻由明到暗个数,并且查看均匀性
// uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (length > 1)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// //test_point.push_back(it.pos());
// //showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
// }
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && (test_lines.size() >= T))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //for (int n = 0; n < test_point.size(); n++)
// //{
// // showMat.at<cv::Vec3b>(test_point[n]) = cv::Vec3b(0, 0, 255);
// //}
// //std::cout << "xx" << std::endl;
// }
// } // }
// else return FUNC_NOT_ENOUGH_MEM; // //对四个方向进行进一步进行过滤,黑白间隔跨度阈值限定
// //分配码型所需内存 // if ((!iFlag))
// tpResult.lpszType = (char *)CoTaskMemAlloc(512);
// if (NULL != tpResult.lpszType)
// { // {
// char file[512] = { 0 }; // colors[vPts[c].Label] = 0;
// sprintf_s(file, "%s", decodeResults[i].strResultType.c_str());
// strcpy(tpResult.lpszType, file);
// } // }
// else return FUNC_NOT_ENOUGH_MEM;
// //添加结果
// tpResults->push_back(tpResult);
//} //}
//*hResults = tpResults->data(); //二次过滤
//*ipNum = static_cast<int>(tpResults->size());
//*hObject = reinterpret_cast<IntPtr>(tpResults);
////膨胀区域
//cv::morphologyEx(binary, binaryEx, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
return FUNC_OK;
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
//cv::Mat binPrev;
//cv::morphologyEx(label, binPrev, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iBlockSize, iBlockSize)));
////用于轮廓检测(最终过滤过的图)
//std::vector<cv::Vec4i> hierarchy;
//std::vector<std::vector<cv::Point>> contourAll, contourFilter;
//findContours(binPrev, contourAll, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
//{
// cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
// double dRate = rect.size.width / rect.size.height;
// std::vector<cv::Point> approx;
// cv::approxPolyDP(cv::Mat(contourAll[i]), approx, cv::arcLength(cv::Mat(contourAll[i]), true)*0.02, true);
// //满足四边形条件
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && (approx.size() >= 4 && approx.size() < 8) && (cv::contourArea(contourAll[i]) > std::pow(iBlockSize * 12 * (1. - dToleErr), 2)))
// {
// contourFilter.push_back(contourAll[i]);
// }
//}
//if (contourFilter.size() < 1)
//{
// return FUNC_CANNOT_CALC;
//}
//计算导数
cv::Mat dx, dy, mag;
cv::Sobel(srcPrev, dx, CV_32F, 1, 0);
cv::Sobel(srcPrev, dy, CV_32F, 0, 1);
//计算梯度幅值
cv::magnitude(dx, dy, mag);
// 归一化
cv::normalize(mag, mag, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(mag, srcPrev);
//二值化
cv::threshold(srcPrev, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//膨胀
cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//计算角点响应
cv::Mat harMap;
cv::cornerHarris(src, harMap, cvRound(iBlockSize*dScaleUpAndDown), 3, 0.04);
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
//计算背景像素
const int histSize = 256;
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
cv::Mat hist;
cv::calcHist(&harMap, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//m1用于检测一维码;m2用于检测二维码
cv::Mat /*m1(Y, X, CV_8UC1, cv::Scalar(0)),*/ m2(iY, iX, CV_8UC1, cv::Scalar(0));
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < iX; x++)
{
if (harMap.ptr<uint8_t>(y)[x] < maxIdx[0])
{
s1.ptr<uint8_t>(y)[x] = 255;
}
else if (harMap.ptr<uint8_t>(y)[x] > maxIdx[0])
{
s2.ptr<uint8_t>(y)[x] = 255;
}
}
}
});
if (addOneDReader)
{
//测试用
cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
cv::Mat binFilter;
cv::adaptiveThreshold(realSrc, binFilter, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, iBlockSize, 2);
//去掉非条码部分
cv::bitwise_and(binFilter, binary, binFilter);
//连通域分析
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(binFilter, labels, stats, centroids);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double maxSize = cv::max(stats.ptr<int>(i)[cv::CC_STAT_WIDTH], stats.ptr<int>(i)[cv::CC_STAT_HEIGHT]);
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < 15) | (maxSize < iBlockSize*(1. + dToleErr)) | (maxSize > 25 * iBlockSize))
{
colors[i] = 0;
}
}
//过滤
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = binFilter.ptr<uint8_t>(y);
for (int x = 0; x < iX; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
cv::Mat back4Filter = binFilter.clone();
//cv::cvtColor(back4Filter, showMat, cv::COLOR_GRAY2BGR);
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(binFilter, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//初步过滤
for (int i = 0; i < int(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
double dRate = (double)cv::max(rect.size.height, rect.size.width) / (double)cv::min(rect.size.height, rect.size.width), rgt = cv::contourArea(contourAll[i]) / rect.size.area();
if (!(cv::min(rect.size.height, rect.size.width) > iBlockSize * 4) && (cv::contourArea(contourAll[i]) / rect.size.area()) > 0.35)
{
contourFilter.push_back(contourAll[i]);
}
else
cv::drawContours(binFilter, contourAll, i, cv::Scalar(0), -1);
}
const float tipLength = 128;
for (int c = 0; c < 8; c++)
{
std::vector<cv::Point> approx;
//符合条件,继续增加比例过滤条件
for (int i = 0; i < int(contourFilter.size()); i++)
{
//首先进行四边形过滤
cv::approxPolyDP(cv::Mat(contourFilter[i]), approx, cv::arcLength(cv::Mat(contourFilter[i]), true)*0.02, true);
if (approx.size() > 10)
{
cv::drawContours(binFilter, contourFilter, i, cv::Scalar(0), -1);
continue;
}
cv::RotatedRect rect = cv::minAreaRect(contourFilter[i]);
cv::Point2f pts[4];
rect.points(pts);
//起点、终点、中点
cv::Point ptStart, ptEnd, ptMid;
if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2]))
{
ptStart = cv::Point((pts[0] + pts[3]) / 2.); ptEnd = cv::Point((pts[1] + pts[2]) / 2.);
}
else
{
ptStart = cv::Point((pts[0] + pts[1]) / 2.); ptEnd = cv::Point((pts[2] + pts[3]) / 2.);
}
ptMid = (ptStart + ptEnd) / 2;
double _angle = std::atan2(-(ptEnd.x - ptStart.x), ptEnd.y - ptStart.y);
cv::Point pt[2];
pt[0] = cv::Point(cvRound(ptMid.x + tipLength * cos(_angle)),
cvRound(ptMid.y + tipLength * sin(_angle)));
pt[1] = cv::Point(cvRound(ptMid.x + tipLength * cos(_angle + CV_PI)),
cvRound(ptMid.y + tipLength * sin(_angle + CV_PI)));
//防止越界
for (int n = 0; n < 2; n++)
{
if (pt[n].x < 0) pt[n].x = 0; if (pt[n].x >= iX - 1) pt[n].x = int(iX - 1); if (pt[n].y < 0) pt[n].y = 0; if (pt[n].y >= iY - 1) pt[n].y = int(iY - 1);
}
bool bFit = false;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
for (int ii = 0; ii < 2; ii++)
{
int flags = 0;
double test_line[6]{ 0 };
cv::LineIterator it(back4Filter, ptMid, pt[ii], 4);
uint8_t future_pixel = back4Filter.ptr<uint8_t>(ptMid.y)[ptMid.x];
for (int n = 0; n < it.count; n++, ++it)
{
//统计均匀性
uint8_t next_pixel = back4Filter.ptr<uint8_t>(it.pos().y)[it.pos().x];
//统计黑白像素
test_line[flags]++;
if (next_pixel != future_pixel)
{
flags++;
future_pixel = 255 - future_pixel;
if (flags == 6) { break; }
}
}
//满足比例
double dRate = cv::min((test_line[0] + test_line[2] + test_line[4]), (test_line[1] + test_line[3] + test_line[5])) / cv::max((test_line[0] + test_line[2] + test_line[4]), (test_line[1] + test_line[3] + test_line[5]));
if (dRate >= (1. - dToleErr*1.5) && dRate <= (1. + dToleErr*1.5) && flags >= 6)
{
bFit = true;
//符合条码特征
break;
}
}
if (!bFit)
{
//不符合条码特征
cv::drawContours(binFilter, contourFilter, i, cv::Scalar(0), -1);
}
}
findContours(binFilter, contourFilter, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
back4Filter = binFilter;
}
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//最大宽度限制
double minLen = cv::min(rect.size.height, rect.size.width);
if (minLen < 8.*iBlockSize*dScaleUpAndDown*(1. + dToleErr))
{
//增加比例过滤条件
cv::Point2f pts[4];
rect.points(pts);
//起点、终点、中点
cv::Point ptStart, ptEnd, ptMid;
if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2]))
{
ptStart = cv::Point((pts[0] + pts[3]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[1] + pts[2]) / 2. / dScaleUpAndDown);
}
else
{
ptStart = cv::Point((pts[0] + pts[1]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[2] + pts[3]) / 2. / dScaleUpAndDown);
}
ptMid = (ptStart + ptEnd) / 2;
cv::LineIterator it(binFilter, (ptMid + ptEnd) / 2, (ptMid + ptStart) / 2, 4);
double dis = cv::norm((ptMid + ptEnd) / 2 - (ptMid + ptStart) / 2);
uint8_t future_pixel = 255;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
int flag = 0;
double test_line[2]{ 0 };
for (int n = 0; n < it.count; n++, ++it)
{
if (s1.ptr<uint8_t>(cvRound(it.pos().y * dScaleUpAndDown))[cvRound(it.pos().x * dScaleUpAndDown)] == 0) continue;
//统计均匀性
uint8_t next_pixel = binFilter.ptr<uint8_t>(it.pos().y)[it.pos().x];
test_line[next_pixel % 254]++;
if (next_pixel != future_pixel)
{
flag++;
future_pixel = 255 - future_pixel;
}
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
}
//满足比例
double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flag > cvRound((dis / 4.)*(1. - dToleErr)))
{
cv::Point2f pt[4];
cv::Size size(cvRound(cv::max(rect.size.height, rect.size.width) + iBlockSize*dScaleUpAndDown / 4.), cvRound(cv::min(rect.size.height, rect.size.width)));
//获取roi位置
double _angle = std::atan2((ptEnd.y - ptStart.y), (ptEnd.x - ptStart.x));
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
pt[0].x = rect.center.x - a*size.height - b*size.width;
pt[0].y = rect.center.y + b*size.height - a*size.width;
pt[1].x = rect.center.x + a*size.height - b*size.width;
pt[1].y = rect.center.y - b*size.height - a*size.width;
pt[2].x = 2 * rect.center.x - pt[0].x;
pt[2].y = 2 * rect.center.y - pt[0].y;
pt[3].x = 2 * rect.center.x - pt[1].x;
pt[3].y = 2 * rect.center.y - pt[1].y;
//防止越界
for (int n = 0; n < 4; n++)
{
if (pt[n].x < 0) pt[n].x = 0.f; if (pt[n].x >= iX - 1) pt[n].x = float(iX - 1); if (pt[n].y < 0) pt[n].y = 0.f; if (pt[n].y >= iY - 1) pt[n].y = float(iY - 1);
}
//用采样的方式提取待解码区域
cv::LineIterator itStHeight(realSrc, pt[0], pt[1], 4);
cv::LineIterator itEdHeight(realSrc, pt[3], pt[2], 4);
cv::LineIterator itStWidth(realSrc, pt[0], pt[3], 4);
cv::LineIterator itEdWidth(realSrc, pt[1], pt[2], 4);
struct Track
{
cv::Point PosS;
cv::Point PosE;
Track() {};
Track(cv::Point PosS, cv::Point PosE) :PosS(PosS), PosE(PosE) {};
};
std::vector<Track> pairStEd(cv::min(itStHeight.count, itEdHeight.count));
for (int n = 0; n < pairStEd.size(); n++, ++itStHeight, ++itEdHeight)
{
pairStEd[n] = Track(itStHeight.pos(), itEdHeight.pos());
}
int iSamplingStep = int(pairStEd.size()) / 4;
//线采样
cv::Mat srcSampling(cv::Size(cv::max(itStWidth.count, itEdWidth.count), 1), CV_8UC1, cv::Scalar(255));
//
std::vector<cv::Mat> oneDMats;
//行
for (int n = 0; n < (int)pairStEd.size(); n += iSamplingStep)
{
cv::LineIterator it(realSrc, pairStEd[n].PosS, pairStEd[n].PosE, 4);
for (int nn = 0; nn < it.count; nn++, ++it)//列
{
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
srcSampling.ptr<uint8_t>(0)[nn] = realSrc.ptr<uint8_t>(it.pos().y)[it.pos().x];
}
//判断是否为二维码
cv::Mat testMat;
cv::threshold(srcSampling, testMat, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
//
cv::Mat testLabels;
if (cv::connectedComponents(testMat, testLabels) < 6)
{
//判断非二维码
break;
}
//扩展
cv::Mat waitArea;
cv::copyMakeBorder(srcSampling, waitArea, 0, 1, 60, 60, cv::BORDER_REPLICATE);
oneDMats.push_back(waitArea);
}
//存储一维码待解码区域
if ((int)oneDMats.size() > 0)
{
//画图
for (int j = 0; j < 4; j++)
{
cv::line(showMat, pt[j], pt[(j + 1) % 4], cv::Scalar(0, 255, 255), 1);
}
//cv::circle(showMat, pt[0], 2, cv::Scalar(255, 0, 0), -1);
//cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 0), -1);
//cv::circle(showMat, pt[2], 2, cv::Scalar(0, 0, 255), -1);
waitAreas.push_back(WaitArea(cv::Mat(), ptMid, getThreshVal_Otsu_8u(oneDMats[0]), _angle*180. / PI, true, oneDMats));
}
}
}
}
}
if (addTwoDReader)
{
//断裂处连接在一起
cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown), cvRound(iBlockSize*dScaleUpAndDown))));
//去掉无关区域
cv::bitwise_and(binary, m2, m2);
//对二值图像过滤
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(m2, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT];
if ((!(dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))) | (stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr))\
| ((double)stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize / 2, 2) * 15))
{
colors[i] = 0;
}
}
//第一次过滤
cv::parallel_for_(cv::Range(0, iY), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = m2.ptr<uint8_t>(y);
for (int x = 0; x < iX; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(m2, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//满足矩形条件与面积条件
double dRate = cv::min(rect.size.width, rect.size.height) / cv::max(rect.size.height, rect.size.width);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && ((double)rect.size.width > double(8. * iBlockSize*dScaleUpAndDown)) && ((double)rect.size.height > double(8. * iBlockSize*dScaleUpAndDown)))
{
contourFilter.push_back(contourAll[i]);
}
}
for (int i = 0; i < contourFilter.size(); i++)
{
cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
//外包矩形
int dynSize = cvRound(cv::max((double)rect.size().height / dScaleUpAndDown, (double)rect.size().width / dScaleUpAndDown));
//疑似二维码区域
cv::Mat waitArea = realSrc(cv::Range(cv::max(0, cvRound(rRect.center.y / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(realSrc.rows - 1, cvRound(rRect.center.y / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(realSrc.cols - 1, cvRound(rRect.center.x / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)))).clone();
//处理后再压入识别
waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rRect.center.x / dScaleUpAndDown), cvRound(rRect.center.y / dScaleUpAndDown)), 0, 0, false, std::vector<cv::Mat>()));
//画图
cv::rectangle(showMat, rect, cv::Scalar(0, 255, 0), 1);
}
}
return FUNC_OK;
}
int eyemCalcDetectParameter(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, bool bTrainOneD, int iBlockSize, int *ipNum, int *iSymbolMin, int *iSymbolMax)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, tpImage.iDepth, tpImage.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
//提取ROI
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight));
//用于显示
cv::Mat showMat;
cv::cvtColor(src, showMat, cv::COLOR_GRAY2BGR);
//图像尺寸
int X = src.cols, Y = src.rows;
//高斯滤波去噪
cv::Mat srcPrev, binary;
cv::GaussianBlur(src, srcPrev, cv::Size(iBlockSize, iBlockSize), 0.3);
//计算角点响应
cv::Mat harMap;
cv::cornerHarris(src, harMap, iBlockSize, 3, 0.04);
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
//计算背景像素
const int histSize = 256;
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
cv::Mat hist;
cv::calcHist(&harMap, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//m1用于检测一维码;m2用于检测二维码
cv::Mat m1(Y, X, CV_8UC1, cv::Scalar(0)), m2(Y, X, CV_8UC1, cv::Scalar(0));
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
if (harMap.ptr<uint8_t>(y)[x] < maxIdx[0])
{
m1.ptr<uint8_t>(y)[x] = 255;
}
else if (harMap.ptr<uint8_t>(y)[x] > maxIdx[0])
{
m2.ptr<uint8_t>(y)[x] = 255;
}
}
}
});
//允许误差
const double dToleErr = 0.35;
//所有解码内容
std::vector<DecodeResult> decodeResults;
//待解码区域,区分条码类型来识别
std::vector<WaitArea> waitAreas;
//是否是计算一维码参数
if (bTrainOneD)
{
//对于一维码如何确定参数,暂时按照能识别到的个数来判断
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(m1, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < 20) | (m1.ptr<uint8_t>(cvRound(centroids.ptr<double>(i)[1]))[cvRound(centroids.ptr<double>(i)[0])] == 0))
{
colors[i] = 0;
}
}
//过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = m1.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//用于过滤非条码部分
cv::Mat binFilter;
cv::adaptiveThreshold(src, binFilter, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, iBlockSize, 5);
//处理断裂一维码
cv::morphologyEx(m1, m1, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(m1, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//最大宽度限制
double minLen = cv::min(rect.size.height, rect.size.width);
if (minLen < 8.*iBlockSize*(1. + dToleErr))
{
//增加比例过滤条件
cv::Point2f pts[4];
rect.points(pts);
//起点、终点、中点
cv::Point ptStart, ptEnd, ptMid;
if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2]))
{
ptStart = cv::Point((pts[0] + pts[3]) / 2.); ptEnd = cv::Point((pts[1] + pts[2]) / 2.);
}
else
{
ptStart = cv::Point((pts[0] + pts[1]) / 2.); ptEnd = cv::Point((pts[2] + pts[3]) / 2.);
}
ptMid = (ptStart + ptEnd) / 2;
cv::LineIterator it(binFilter, (ptMid + ptEnd) / 2, (ptMid + ptStart) / 2, 4);
double dis = cv::norm((ptMid + ptEnd) / 2 - (ptMid + ptStart) / 2);
uint8_t future_pixel = 255;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
int flag = 0;
double test_line[2]{ 0 };
for (int n = 0; n < it.count; n++, ++it)
{
if (m1.ptr<uint8_t>(cvRound(it.pos().y))[cvRound(it.pos().x)] == 0) continue;
//统计均匀性
uint8_t next_pixel = binFilter.ptr<uint8_t>(it.pos().y)[it.pos().x];
test_line[next_pixel % 254]++;
if (next_pixel != future_pixel)
{
flag++;
future_pixel = 255 - future_pixel;
}
}
//满足比例
double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flag > cvRound((dis / 4.)*(1. - dToleErr)))
{
cv::Point2f pt[4];
cv::Size size(cvRound(cv::max(rect.size.height, rect.size.width) + iBlockSize / 4.), cvRound(cv::min(rect.size.height, rect.size.width)));
//获取roi位置
double _angle = std::atan2((ptEnd.y - ptStart.y), (ptEnd.x - ptStart.x));
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
pt[0].x = rect.center.x - a*size.height - b*size.width;
pt[0].y = rect.center.y + b*size.height - a*size.width;
pt[1].x = rect.center.x + a*size.height - b*size.width;
pt[1].y = rect.center.y - b*size.height - a*size.width;
pt[2].x = 2 * rect.center.x - pt[0].x;
pt[2].y = 2 * rect.center.y - pt[0].y;
pt[3].x = 2 * rect.center.x - pt[1].x;
pt[3].y = 2 * rect.center.y - pt[1].y;
//防止越界
for (int n = 0; n < 4; n++)
{
if (pt[n].x < 0) pt[n].x = 0.f; if (pt[n].x >= X - 1) pt[n].x = float(X - 1); if (pt[n].y < 0) pt[n].y = 0.f; if (pt[n].y >= Y - 1) pt[n].y = float(Y - 1);
}
//用采样的方式提取待解码区域
cv::LineIterator itStHeight(src, pt[0], pt[1], 4);
cv::LineIterator itEdHeight(src, pt[3], pt[2], 4);
cv::LineIterator itStWidth(src, pt[0], pt[3], 4);
cv::LineIterator itEdWidth(src, pt[1], pt[2], 4);
struct Track
{
cv::Point PosS;
cv::Point PosE;
Track() {};
Track(cv::Point PosS, cv::Point PosE) :PosS(PosS), PosE(PosE) {};
};
std::vector<Track> pairStEd(cv::min(itStHeight.count, itEdHeight.count));
for (int n = 0; n < pairStEd.size(); n++, ++itStHeight, ++itEdHeight)
{
pairStEd[n] = Track(itStHeight.pos(), itEdHeight.pos());
}
int iSamplingStep = int(pairStEd.size()) / 4;
//线采样
cv::Mat srcSampling(cv::Size(cv::max(itStWidth.count, itEdWidth.count), 1), CV_8UC1, cv::Scalar(255));
//
std::vector<cv::Mat> oneDMats;
//行
for (int n = 0; n < (int)pairStEd.size(); n += iSamplingStep)
{
cv::LineIterator it(src, pairStEd[n].PosS, pairStEd[n].PosE, 4);
for (int nn = 0; nn < it.count; nn++, ++it)//列
{
srcSampling.ptr<uint8_t>(0)[nn] = src.ptr<uint8_t>(it.pos().y)[it.pos().x];
}
//判断是否为二维码
cv::Mat testMat;
cv::threshold(srcSampling, testMat, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
//
cv::Mat testLabels;
if (cv::connectedComponents(testMat, testLabels) < 6)
{
//判断非二维码
break;
}
//扩展
cv::Mat waitArea;
cv::copyMakeBorder(srcSampling, waitArea, 0, 1, 60, 60, cv::BORDER_REPLICATE);
oneDMats.push_back(waitArea);
}
//存储一维码待解码区域
if ((int)oneDMats.size() > 0)
{
waitAreas.push_back(WaitArea(cv::Mat(), ptMid, getThreshVal_Otsu_8u(oneDMats[0]), _angle*180. / PI, true, oneDMats));
}
}
}
}
}
else
{
//按照识别到码的定位块尺寸来确定参数,如果是DM码该如何确定参数?
//断裂处连接在一起
cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(iBlockSize, iBlockSize)));
//去掉无关区域
cv::bitwise_and(binary, m2, m2);
//对二值图像过滤
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(m2, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT];
if ((!(dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))) | (stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize * 15 * 1.414*(1. + dToleErr))\
| ((double)stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize / 2, 2) * 15))
{
colors[i] = 0;
}
}
//第一次过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = m2.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(m2, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//满足矩形条件与面积条件
double dRate = cv::min(rect.size.width, rect.size.height) / cv::max(rect.size.height, rect.size.width);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && ((double)rect.size.width > double(8. * iBlockSize)) && ((double)rect.size.height > double(8. * iBlockSize)))
{
contourFilter.push_back(contourAll[i]);
}
}
for (int i = 0; i < contourFilter.size(); i++)
{
cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
//外包矩形
int dynSize = cvRound(cv::max((double)rect.size().height, (double)rect.size().width));
//疑似二维码区域
cv::Mat waitArea = src(cv::Range(cv::max(0, cvRound(rRect.center.y) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(Y - 1, cvRound(rRect.center.y) + cvRound(4.*(double)iBlockSize + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x) - cvRound(4.*(double)iBlockSize + dynSize / 2)), cv::min(X - 1, cvRound(rRect.center.x) + cvRound(4.*(double)iBlockSize + dynSize / 2)))).clone();
//处理后再压入识别
waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rRect.center.x), cvRound(rRect.center.y)), 0, 0, false, std::vector<cv::Mat>()));
}
}
std::vector<std::string> hints_ = { "AZTEC","CODABAR","CODE_39","CODE_93","CODE_128","DATA_MATRIX","EAN_8","EAN_13","ITF","MAXICODE","PDF_417","QR_CODE","RSS_14","RSS_EXPANDED","UPC_A","UPC_E","UPC_EAN_EXTENSION" };
//解码
decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, 10, 1.0);
return FUNC_OK; return FUNC_OK;
} }
......
...@@ -88,7 +88,7 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages ...@@ -88,7 +88,7 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
int totalFrmNum = cap.get(cv::CAP_PROP_FRAME_COUNT); int totalFrmNum = cap.get(cv::CAP_PROP_FRAME_COUNT);
std::vector<cv::Mat> *pFrames = new std::vector<cv::Mat>(); std::vector<EyemImage> *pFrames = new std::vector<EyemImage>();
cv::Mat nextImg; cv::Mat nextImg;
while (true) while (true)
...@@ -97,13 +97,79 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages ...@@ -97,13 +97,79 @@ int eyemVideoCapture(const char *fileName, IntPtr *hObject, EyemImage **tpImages
if (nextImg.empty()) if (nextImg.empty())
break; break;
//图像信息
EyemImage tpImage;
tpImage.iWidth = nextImg.cols; tpImage.iHeight = nextImg.rows; tpImage.iDepth = nextImg.depth(); tpImage.iChannels = nextImg.channels();
pFrames->push_back(nextImg); //内存尺寸
int _Size = tpImage.iWidth*tpImage.iHeight*tpImage.iChannels;
//需要申请内存
switch (tpImage.iDepth)
{
case CV_8U:
_Size *= sizeof(uint8_t);
tpImage.vpImage = (uint8_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_8S:
_Size *= sizeof(int8_t);
tpImage.vpImage = (int8_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_16U:
_Size *= sizeof(uint16_t);
tpImage.vpImage = (uint16_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_16S:
_Size *= sizeof(int16_t);
tpImage.vpImage = (int16_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_32S:
_Size *= sizeof(int32_t);
tpImage.vpImage = (int32_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_32F:
_Size *= sizeof(float_t);
tpImage.vpImage = (float_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
case CV_64F:
_Size *= sizeof(double_t);
tpImage.vpImage = (double_t *)malloc(_Size);
if (NULL == tpImage.vpImage)
return FUNC_NOT_ENOUGH_MEM;
memset(tpImage.vpImage, 0, _Size);
break;
default:
//no support format
return FUNC_CANNOT_USE;
}
//拷贝数据
memcpy(tpImage.vpImage, nextImg.data, _Size);
//
pFrames->push_back(tpImage);
} }
//*tpImages = pFrames->data(); *tpImages = pFrames->data();
//*ipNum = static_cast<int>(pFrames->size()); *ipNum = static_cast<int>(pFrames->size());
//*hObject = dynamic_cast<IntPtr>(); *hObject = reinterpret_cast<IntPtr>(pFrames);
return FUNC_OK; return FUNC_OK;
} }
...@@ -801,7 +867,14 @@ void eyemImageFree(EyemImage &tpImage) ...@@ -801,7 +867,14 @@ void eyemImageFree(EyemImage &tpImage)
int eyemVideoCaptureFree(IntPtr hObject) int eyemVideoCaptureFree(IntPtr hObject)
{ {
std::vector<cv::Mat> *tpImages = reinterpret_cast<std::vector<cv::Mat>*>(hObject); std::vector<EyemImage> *tpImages = reinterpret_cast<std::vector<EyemImage>*>(hObject);
for (std::vector<EyemImage>::iterator it = tpImages->begin(); it != tpImages->end(); ++it)
{
EyemImage tpImage = (*it);
tpImage.iWidth = tpImage.iHeight = tpImage.iDepth = tpImage.iChannels = 0;
free(tpImage.vpImage), tpImage.vpImage = NULL;
}
delete tpImages; delete tpImages;
tpImages = NULL; tpImages = NULL;
return true; return true;
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!