Commit 33393dbb 张士柳

1 个父辈 f2f74c45
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace eyemLib_Sharp
{
public class YoloWrapper : IDisposable
{
private const int MaxObjects = 1000;
[DllImport("yolo_cpp_dll.dll", EntryPoint = "init")]
private static extern int InitializeYolo(string configurationFilename, string weightsFilename, int gpu);
[DllImport("yolo_cpp_dll.dll", EntryPoint = "detect_image")]
private static extern int DetectImage(string filename, ref BboxContainer container);
[DllImport("yolo_cpp_dll.dll", EntryPoint = "detect_mat")]
private static extern int DetectImage(IntPtr pArray, int nSize, ref BboxContainer container);
[DllImport("yolo_cpp_dll.dll", EntryPoint = "dispose")]
private static extern int DisposeYolo();
[StructLayout(LayoutKind.Sequential)]
public struct bbox_t
{
public UInt32 x, y, w, h; // (x,y) - top-left corner, (w, h) - width & height of bounded box
public float prob; // confidence - probability that the object was found correctly
public UInt32 obj_id; // class of object - from range [0, classes-1]
public UInt32 track_id; // tracking id for video (0 - untracked, 1 - inf - tracked object)
public UInt32 frames_counter;
public float x_3d, y_3d, z_3d; // 3-D coordinates, if there is used 3D-stereo camera
};
[StructLayout(LayoutKind.Sequential)]
public struct BboxContainer
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxObjects)]
public bbox_t[] candidates;
}
public YoloWrapper(string configurationFilename, string weightsFilename, int gpu)
{
InitializeYolo(configurationFilename, weightsFilename, gpu);
}
public void Dispose()
{
DisposeYolo();
}
public bbox_t[] Detect(string filename)
{
var container = new BboxContainer();
var count = DetectImage(filename, ref container);
return container.candidates;
}
public bbox_t[] Detect(byte[] imageData)
{
var container = new BboxContainer();
var size = Marshal.SizeOf(imageData[0]) * imageData.Length;
var pnt = Marshal.AllocHGlobal(size);
try
{
// Copy the array to unmanaged memory.
Marshal.Copy(imageData, 0, pnt, imageData.Length);
var count = DetectImage(pnt, imageData.Length, ref container);
if (count == -1)
{
throw new NotSupportedException($"{"yolo_cpp_dll.dll"} has no OpenCV support");
}
}
catch (Exception exception)
{
return null;
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
}
return container.candidates;
}
}
}
...@@ -773,6 +773,12 @@ namespace eyemLib_Sharp ...@@ -773,6 +773,12 @@ namespace eyemLib_Sharp
//释放解码句柄 //释放解码句柄
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern bool eyemDetectAndDecodeFree(IntPtr hObject); private static extern bool eyemDetectAndDecodeFree(IntPtr hObject);
//基于深度学习读码程序(仅支持QR、DataMatrix)
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, int iBlockSize, int iRangeC, double dMinorStep = 1.0);
//加载模型配置文件
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemInitNNDataCodeModel(string detectorConfigPath, string detectorModelPath, string superResolutionConfigPath, string superResolutionModelPath);
//背景变化跟踪 //背景变化跟踪
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, IntPtr tpArray, int iArraySize, IntPtr ipResults, out EyemImage tpDstImg); private static extern int eyemTrackFeature(EyemImage tpRefImg, EyemImage tpNextImg, IntPtr tpArray, int iArraySize, IntPtr ipResults, out EyemImage tpDstImg);
...@@ -788,6 +794,7 @@ namespace eyemLib_Sharp ...@@ -788,6 +794,7 @@ namespace eyemLib_Sharp
//测试接口 //测试接口
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemLibImpl(EyemImage tpImage, out EyemImage tpDstImg); private static extern int eyemLibImpl(EyemImage tpImage, out EyemImage tpDstImg);
#endregion #endregion
#region 日志功能 #region 日志功能
...@@ -861,7 +868,10 @@ namespace eyemLib_Sharp ...@@ -861,7 +868,10 @@ namespace eyemLib_Sharp
//flag = eyemImageAbs(image1, ref tpDstImg); //flag = eyemImageAbs(image1, ref tpDstImg);
flag = eyemLibImpl(image, out tpDstImg); //flag = eyemLibImpl(image, out tpDstImg);
flag = eyemInitNNDataCodeModel(".\\darknet\\yolov3-detect-tiny.cfg", ".\\darknet\\yolov3-detect-tiny_last.weights", "", "");
#region Test Blob #region Test Blob
...@@ -1072,7 +1082,7 @@ namespace eyemLib_Sharp ...@@ -1072,7 +1082,7 @@ namespace eyemLib_Sharp
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS","" //"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS",""
//eyemCountObject(image, tpRoi, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg); //eyemCountObject(image, tpRoi, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), 0.1, "", 100, 7, ref pNumObj, out tpDstImg); //eyemCountObjectIrregularParts(image, tpRoi, file.Replace(".png", ""), 0.1, "IP_LARGE_PARTS", 100, 7, ref pNumObj, out tpDstImg);
//eyemCountObjectE(image, tpRoi, fileName, ref pNumObj, out tpDstImg); //eyemCountObjectE(image, tpRoi, fileName, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ref pNumObj, out tpDstImg); //eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), tpModels[0], hModelID, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, out tpDstImg); //eyemCountObjectIrregularPartsE(image, tpRoi, file.Replace(".png", ""), "D:\\模板文件\\" + /*file.Replace(".png", ".tpl")*/"74d571ed-9fd4-4959-85dd-3195261e4b48.tpl", ref pNumObj, out tpDstImg);
...@@ -1088,8 +1098,8 @@ namespace eyemLib_Sharp ...@@ -1088,8 +1098,8 @@ namespace eyemLib_Sharp
//} //}
////<解码测试 ////<解码测试
//int ipNum; EyemBarCode* tpResults; int ipNum; EyemBarCode* tpResults;
//DataCodeHandle hObject; DataCodeHandle hObject;
//int iRes = eyemDetectAndDecode(image, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX", out hObject, out tpResults, out ipNum, false, 11, 5, 128, 256); //int iRes = eyemDetectAndDecode(image, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX", out hObject, out tpResults, out ipNum, false, 11, 5, 128, 256);
//for (int i = 0; i < ipNum; i++) //for (int i = 0; i < ipNum; i++)
//{ //{
...@@ -1098,6 +1108,8 @@ namespace eyemLib_Sharp ...@@ -1098,6 +1108,8 @@ namespace eyemLib_Sharp
//} //}
//hObject.Dispose(); //hObject.Dispose();
flag = eyemDetectAndDecodeUseNN(image, tpRoi, out hObject, out tpResults, out ipNum, 11, 5);
sw.Stop(); sw.Stop();
Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + ",结果:" + pNumObj); Console.WriteLine(file + "--->" + "耗时:" + sw.ElapsedMilliseconds.ToString() + ",结果:" + pNumObj);
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Darknet.cs" />
<Compile Include="EyemLib.cs" /> <Compile Include="EyemLib.cs" />
<Compile Include="EyemLibDemo.cs" /> <Compile Include="EyemLibDemo.cs" />
<Compile Include="log4cpp\ILog4CPP.cs" /> <Compile Include="log4cpp\ILog4CPP.cs" />
......
#include "align.h"
namespace wechat_qrcode {
Align::Align() { rotate90_ = false; }
cv::Mat Align::calcWarpMatrix(const cv::Mat src, const cv::Mat dst) {
M_ = getPerspectiveTransform(src, dst);
M_inv_ = M_.inv();
return M_;
}
std::vector<cv::Point2f> Align::warpBack(const std::vector<cv::Point2f> &dst_pts) {
std::vector<cv::Point2f> src_pts;
for (size_t j = 0; j < dst_pts.size(); j++) {
auto src_x = (rotate90_ ? dst_pts[j].y : dst_pts[j].x) + crop_x_;
auto src_y = (rotate90_ ? dst_pts[j].x : dst_pts[j].y) + crop_y_;
src_pts.push_back(cv::Point2f(src_x, src_y));
}
return src_pts;
}
cv::Mat Align::crop(const cv::Mat &inputImg, const int width, const int height) {
cv::Mat warp_dst = cv::Mat::zeros(height, width, inputImg.type());
warpPerspective(inputImg, warp_dst, M_, warp_dst.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, 255);
return warp_dst;
}
cv::Mat Align::crop(const cv::Mat &inputImg, const cv::Mat &srcPts, const float paddingW, const float paddingH,
const int minPadding) {
int x0 = srcPts.at<float>(0, 0);
int y0 = srcPts.at<float>(0, 1);
int x2 = srcPts.at<float>(2, 0);
int y2 = srcPts.at<float>(2, 1);
int width = x2 - x0 + 1;
int height = y2 - y0 + 1;
int padx = cv::max(paddingW * width, static_cast<float>(minPadding));
int pady = cv::max(paddingH * height, static_cast<float>(minPadding));
crop_x_ = cv::max(x0 - padx, 0);
crop_y_ = cv::max(y0 - pady, 0);
int end_x = cv::min(x2 + padx, inputImg.cols - 1);
int end_y = cv::min(y2 + pady, inputImg.rows - 1);
cv::Rect crop_roi(crop_x_, crop_y_, end_x - crop_x_ + 1, end_y - crop_y_ + 1);
cv::Mat dst = inputImg(crop_roi).clone();
if (rotate90_) dst = dst.t(); // transpose
return dst;
}
} // namespace wechat_qrcode
\ No newline at end of file \ No newline at end of file
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __DETECTOR_ALIGN_HPP_
#define __DETECTOR_ALIGN_HPP_
#include <stdio.h>
#include <fstream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
namespace wechat_qrcode {
class Align {
public:
Align();
cv::Mat calcWarpMatrix(const cv::Mat src, const cv::Mat dst);
std::vector<cv::Point2f> warpBack(const std::vector<cv::Point2f> &dst_pts);
cv::Mat crop(const cv::Mat &inputImg, const cv::Mat &srcPts, const float paddingW, const float paddingH,
const int minPadding);
void setRotate90(bool v) { rotate90_ = v; }
private:
cv::Mat crop(const cv::Mat &inputImg, const int width, const int height);
cv::Mat M_;
cv::Mat M_inv_;
int crop_x_;
int crop_y_;
bool rotate90_;
};
} // namespace wechat_qrcode
#endif // __DETECTOR_ALIGN_HPP_
\ No newline at end of file \ No newline at end of file
...@@ -1222,6 +1222,49 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam ...@@ -1222,6 +1222,49 @@ int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileNam
return FUNC_OK; return FUNC_OK;
} }
int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, int iBlockSize, int iRangeC, double dMinorStep)
{
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
//识别
std::vector<cv::Rect> points;
auto ret = detector->detect(image, points);
//解码
for (int i = 0; i < ret.size(); i++)
{
cv::Mat dst;
cv::resize(ret[i], dst, cv::Size(140, 140));
std::vector<cv::Mat> scaled = detector->getScaleMap(dst);
}
//画图
if (image.channels() != 3) {
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
}
for (auto point : points) {
cv::rectangle(image, point, cv::Scalar(0, 255, 0), 2);
}
return FUNC_OK;
}
int eyemInitNNDataCodeModel(const char *detectorConfigPath, const char *detectorModelPath, const char *superResolutionConfigPath, const char *superResolutionModelPath)
{
try
{
detector = cv::makePtr<NNDetector>(detectorConfigPath, detectorModelPath, superResolutionConfigPath, superResolutionModelPath);
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
return FUNC_CANNOT_CALC;
}
return FUNC_OK;
}
bool eyemDetectAndDecodeFree(IntPtr hObject) bool eyemDetectAndDecodeFree(IntPtr hObject)
{ {
std::vector<EyemBarCode> *tpResults = reinterpret_cast<std::vector<EyemBarCode>*>(hObject); std::vector<EyemBarCode> *tpResults = reinterpret_cast<std::vector<EyemBarCode>*>(hObject);
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <numeric> #include <numeric>
#include <omp.h> #include <omp.h>
#include "objectDetection.h"
using namespace zxing; using namespace zxing;
using namespace zxing::qrcode; using namespace zxing::qrcode;
...@@ -56,6 +58,7 @@ enum { ...@@ -56,6 +58,7 @@ enum {
#define enumtoCharArr(val) #val #define enumtoCharArr(val) #val
cv::Ptr<NNDetector> detector;
// //
struct tMap struct tMap
......
...@@ -861,6 +861,12 @@ int eyemImageAbs(EyemImage tpImage, EyemImage &tpDstImg) ...@@ -861,6 +861,12 @@ int eyemImageAbs(EyemImage tpImage, EyemImage &tpDstImg)
return FUNC_OK; return FUNC_OK;
} }
int eyemImageReduce(EyemImage tpImage, EyemImage *tpDstImage)
{
return FUNC_OK;
}
void eyemOpenWindow(const char *winname) void eyemOpenWindow(const char *winname)
{ {
cv::namedWindow("eyemLib", cv::WINDOW_AUTOSIZE); cv::namedWindow("eyemLib", cv::WINDOW_AUTOSIZE);
......
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
#define FUNC_CANNOT_CALC (-100) // 不可计算 #define FUNC_CANNOT_CALC (-100) // 不可计算
#define FUNC_CANNOT_USE (-999) // 不可用 #define FUNC_CANNOT_USE (-999) // 不可用
// 错误代码 (识别解码)
#define FUNC_FAILED_FOUND (-4) // 未识别到
#define FUNC_FAILED_DECODE (-5) // 未能解码
// 错误代码(矩阵计算) // 错误代码(矩阵计算)
#define FUNC_DET_EQ_ZERO (-110) // 矩阵表达式为零 #define FUNC_DET_EQ_ZERO (-110) // 矩阵表达式为零
...@@ -844,6 +849,8 @@ typedef struct { ...@@ -844,6 +849,8 @@ typedef struct {
extern "C" { extern "C" {
#endif #endif
EXPORTS int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **tpResult, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0); EXPORTS int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **tpResult, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
EXPORTS int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, int iBlockSize, int iRangeC, double dMinorStep = 1.0);
EXPORTS int eyemInitNNDataCodeModel(const char *detectorConfigPath, const char *detectorModelPath, const char *superResolutionConfigPath, const char *superResolutionModelPath);
EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject); EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject);
EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObject(EyemImage tpImage, EyemRect tpRoi, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg); EXPORTS int eyemCountObjectE(EyemImage tpImage, EyemRect tpRoi, const char *fileName, LPSTR *lpszNumObj, EyemImage *tpDstImg);
......
...@@ -163,7 +163,6 @@ ...@@ -163,7 +163,6 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="align.h" />
<ClInclude Include="eyemBarCode.h" /> <ClInclude Include="eyemBarCode.h" />
<ClInclude Include="eyemBin.h" /> <ClInclude Include="eyemBin.h" />
<ClInclude Include="eyemCalib.h" /> <ClInclude Include="eyemCalib.h" />
...@@ -177,13 +176,12 @@ ...@@ -177,13 +176,12 @@
<ClInclude Include="eyemMath.h" /> <ClInclude Include="eyemMath.h" />
<ClInclude Include="eyemMisc.h" /> <ClInclude Include="eyemMisc.h" />
<ClInclude Include="eyemSmooth.h" /> <ClInclude Include="eyemSmooth.h" />
<ClInclude Include="objectDetection.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="ssd_detector.h" /> <ClInclude Include="superScale.h" />
<ClInclude Include="super_scale.h" /> <ClInclude Include="yoloWrapper.h" />
<ClInclude Include="wechat_qrcode.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="align.cpp" />
<ClCompile Include="eyemBarCode.cpp" /> <ClCompile Include="eyemBarCode.cpp" />
<ClCompile Include="eyemBin.cpp" /> <ClCompile Include="eyemBin.cpp" />
<ClCompile Include="eyemCalib.cpp" /> <ClCompile Include="eyemCalib.cpp" />
...@@ -201,9 +199,9 @@ ...@@ -201,9 +199,9 @@
<ClCompile Include="eyemMisc.cpp" /> <ClCompile Include="eyemMisc.cpp" />
<ClCompile Include="eyemSmooth.cpp" /> <ClCompile Include="eyemSmooth.cpp" />
<ClCompile Include="libopencv.cpp" /> <ClCompile Include="libopencv.cpp" />
<ClCompile Include="ssd_detector.cpp" /> <ClCompile Include="objectDetection.cpp" />
<ClCompile Include="super_scale.cpp" /> <ClCompile Include="superScale.cpp" />
<ClCompile Include="wechat_qrcode.cpp" /> <ClCompile Include="yoloWrapper.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="eyemLib.rc" /> <ResourceCompile Include="eyemLib.rc" />
......
...@@ -13,9 +13,6 @@ ...@@ -13,9 +13,6 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
<Filter Include="源文件\wechat_qrcode">
<UniqueIdentifier>{df02fcd2-0d49-4313-a9f8-e5e0093807c6}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="eyemLib.h"> <ClInclude Include="eyemLib.h">
...@@ -60,17 +57,14 @@ ...@@ -60,17 +57,14 @@
<ClInclude Include="eyemBarCode.h"> <ClInclude Include="eyemBarCode.h">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="wechat_qrcode.h"> <ClInclude Include="yoloWrapper.h">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="align.h"> <ClInclude Include="objectDetection.h">
<Filter>源文件\wechat_qrcode</Filter> <Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="ssd_detector.h">
<Filter>源文件\wechat_qrcode</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="super_scale.h"> <ClInclude Include="superScale.h">
<Filter>源文件\wechat_qrcode</Filter> <Filter>源文件</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
...@@ -125,17 +119,14 @@ ...@@ -125,17 +119,14 @@
<ClCompile Include="eyemBarCode.cpp"> <ClCompile Include="eyemBarCode.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="wechat_qrcode.cpp"> <ClCompile Include="yoloWrapper.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="align.cpp"> <ClCompile Include="objectDetection.cpp">
<Filter>源文件\wechat_qrcode</Filter> <Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="ssd_detector.cpp">
<Filter>源文件\wechat_qrcode</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="super_scale.cpp"> <ClCompile Include="superScale.cpp">
<Filter>源文件\wechat_qrcode</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -283,7 +283,6 @@ static void loadTrackModel(const char *fileName, cv::OutputArray tplMat, cv::Poi ...@@ -283,7 +283,6 @@ static void loadTrackModel(const char *fileName, cv::OutputArray tplMat, cv::Poi
//上锁 //上锁
logger.t(logModule + "上锁..."); logger.t(logModule + "上锁...");
mtx_misc.lock();
logger.t(logModule + "打开文件..."); logger.t(logModule + "打开文件...");
FILE *fps = NULL; FILE *fps = NULL;
...@@ -315,7 +314,6 @@ static void loadTrackModel(const char *fileName, cv::OutputArray tplMat, cv::Poi ...@@ -315,7 +314,6 @@ static void loadTrackModel(const char *fileName, cv::OutputArray tplMat, cv::Poi
//解锁 //解锁
logger.t(logModule + "解锁..."); logger.t(logModule + "解锁...");
mtx_misc.unlock();
//获取图像数据大小 //获取图像数据大小
logger.t(logModule + "拷贝头数据..."); logger.t(logModule + "拷贝头数据...");
...@@ -1714,7 +1712,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -1714,7 +1712,7 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
} }
} }
}); });
//增强到目标亮度 //增强到目标亮度方便显示
cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh)); cc += cv::Scalar((162 - backThresh), (162 - backThresh), (162 - backThresh));
//去掉干扰 //去掉干扰
cv::Mat binary, srcPrev; cv::Mat binary, srcPrev;
...@@ -3161,9 +3159,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3161,9 +3159,13 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
//方形托盘 //方形托盘
else if (strcmp(ccSubType, "IP_SQUARE_PARTS") == 0) else if (strcmp(ccSubType, "IP_SQUARE_PARTS") == 0)
{ {
//TODO:
}
else if (strcmp(ccSubType, "IP_NORMAL_PARTS") == 0)
{
//TODO:
} }
//普通算法不做其他处理 //适用散料
else else
{ {
//先用自动算法点,如果不行判断为散料 //先用自动算法点,如果不行判断为散料
...@@ -3247,12 +3249,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char ...@@ -3247,12 +3249,6 @@ int eyemCountObjectIrregularParts(EyemImage tpImage, EyemRect tpRoi, const char
double contourArea = cv::contourArea(contours[i]); double contourArea = cv::contourArea(contours[i]);
if (contourArea > 15000) if (contourArea > 15000)
{ {
////去掉中间部分
//cv::Moments mu = cv::moments(contours[i]);
//cv::Point2f reelCenter(float(mu.m10 / mu.m00), float(mu.m01 / mu.m00));
////标记当前位置
//cv::drawMarker(cc, reelCenter, cv::Scalar(0, 255, 0, 255), cv::MARKER_DIAMOND, 15);
//绘制掩膜 //绘制掩膜
cv::drawContours(mask, contours, i, cv::Scalar(255), -1); cv::drawContours(mask, contours, i, cv::Scalar(255), -1);
} }
...@@ -5970,25 +5966,6 @@ int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, i ...@@ -5970,25 +5966,6 @@ int eyemAOIForTSAV(EyemImage tpRefImg, EyemImage tpNextImg, EyemRect3 *tpRois, i
return FUNC_OK; return FUNC_OK;
} }
////绘制预测边界框
//static void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame) {
// //绘制边界框
// cv::rectangle(frame, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(255, 178, 50), 3);
//
// std::string label = cv::format("%.2f", conf);
// if (!classes.empty()) {
// CV_Assert(classId < (int)classes.size());
// label = classes[classId] + ":" + label;//边框上的类别标签与置信度
// }
// //绘制边界框上的标签
// int baseLine;
// cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
// top = std::max(top, labelSize.height);
// cv::rectangle(frame, cv::Point(left, top - round(1.5*labelSize.height)), cv::Point(left + round(1.5*labelSize.width), top + baseLine), cv::Scalar(255, 255, 255), cv::FILLED);
// cv::putText(frame, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 0), 1);
//}
int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
{ {
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone(); cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
...@@ -6000,6 +5977,16 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6000,6 +5977,16 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
cv::cvtColor(image, image, cv::COLOR_BGRA2BGR); cv::cvtColor(image, image, cv::COLOR_BGRA2BGR);
} }
//const int minInputSize = 832;
//float resizeRatio = (float)sqrt(image.cols * image.rows * 1.0 / (minInputSize * minInputSize));
//int target_width = cvRound((float)image.cols / resizeRatio);
//int target_height = cvRound((float)image.rows / resizeRatio);
//cv::Mat input;
//resize(image, input, cv::Size(image.cols / 2, image.rows / 2), 0, 0, cv::INTER_CUBIC);
//image = input;
#pragma region wechat_qrcode #pragma region wechat_qrcode
//cv::Ptr<wechat_qrcode::WeChatQRCode> detector; //cv::Ptr<wechat_qrcode::WeChatQRCode> detector;
...@@ -6020,6 +6007,8 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6020,6 +6007,8 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
#pragma endregion #pragma endregion
#pragma region darknet
//加载类名 //加载类名
std::vector<std::string> classes; std::vector<std::string> classes;
std::string classFile = ".\\darknet\\detect.names"; std::string classFile = ".\\darknet\\detect.names";
...@@ -6030,7 +6019,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6030,7 +6019,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
while (std::getline(ifs, line)) classes.push_back(line); while (std::getline(ifs, line)) classes.push_back(line);
//加载网络 //加载网络
cv::dnn::Net net = cv::dnn::readNet(".\\darknet\\detect.cfg", ".\\darknet\\detect.weights"); cv::dnn::Net net = cv::dnn::readNet(".\\darknet\\yolov3-detect-tiny.cfg", ".\\darknet\\yolov3-detect-tiny_last.weights");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableBackend(cv::dnn::DNN_TARGET_CPU); net.setPreferableBackend(cv::dnn::DNN_TARGET_CPU);
...@@ -6046,16 +6035,14 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6046,16 +6035,14 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
//预处理图像 //预处理图像
cv::Mat blob; cv::Mat blob;
cv::dnn::blobFromImage(image, blob, 1 / 255., cv::Size(416, 416)); cv::dnn::blobFromImage(image, blob, 1 / 255., cv::Size(608, 608));
//为网络输入新值 //为网络输入新值
net.setInput(blob); net.setInput(blob);
double begin0 = (double)cv::getTickCount();
//获取预测结果 //获取预测结果
std::vector<cv::Mat> outputBlobs; std::vector<cv::Mat> outputBlobs;
net.forward(outputBlobs, outBlobNames); net.forward(outputBlobs, outBlobNames);
std::cout << ((double)cv::getTickCount() - begin0) / cv::getTickFrequency() << std::endl;
std::vector<int> classIds;//储存识别类的索引 std::vector<int> classIds;//储存识别类的索引
std::vector<float> confidences;//储存置信度 std::vector<float> confidences;//储存置信度
...@@ -6072,7 +6059,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6072,7 +6059,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
//取得最大分数值与索引 //取得最大分数值与索引
cv::minMaxLoc(prob, 0, &confidence, 0, &classIdPoint); cv::minMaxLoc(prob, 0, &confidence, 0, &classIdPoint);
//如果置信度大于阈值 //如果置信度大于阈值
if (confidence > 0.35) { if (confidence > 0.01) {
cv::Mat dt = outputBlobs[n]; cv::Mat dt = outputBlobs[n];
...@@ -6098,7 +6085,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6098,7 +6085,7 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
std::vector<int> indices; std::vector<int> indices;
//非极大值抑制 //非极大值抑制
cv::dnn::NMSBoxes(bboxes, confidences, 0.5, 0.4, indices); cv::dnn::NMSBoxes(bboxes, confidences, 0.01f, 0.05f, indices);
for (int i = 0; i < indices.size(); i++) { for (int i = 0; i < indices.size(); i++) {
int idx = indices[i]; int idx = indices[i];
...@@ -6137,5 +6124,8 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg) ...@@ -6137,5 +6124,8 @@ int eyemLibImpl(EyemImage tpImage, EyemImage *tpDstImg)
memcpy(tpDstImg->vpImage, image.data, _Size); memcpy(tpDstImg->vpImage, image.data, _Size);
} }
#pragma endregion
return FUNC_OK; return FUNC_OK;
} }
...@@ -12,15 +12,12 @@ ...@@ -12,15 +12,12 @@
#include <tbb\tbb.h> #include <tbb\tbb.h>
#include "wechat_qrcode.h" #include "yoloWrapper.h"
constexpr double c = PI / 180.; constexpr double c = PI / 180.;
std::mutex mtx_misc;
extern Logger logger; extern Logger logger;
extern int killProcessID; extern int killProcessID;
#endif/* __EYEM_MISC_H */ #endif/* __EYEM_MISC_H */
#include "objectDetection.h"
#include "yoloWrapper.h"
#include "superScale.h"
class NNDetector::Impl {
public:
Impl() {}
~Impl() {}
std::vector<cv::Rect> detect(const cv::Mat& img);
std::vector<float> getScaleList(const int width, const int height);
std::shared_ptr<YoloWrapper> detector_;
std::shared_ptr<SuperScale> super_resolution_model_;
};
NNDetector::NNDetector(const std::string & detector_config_path,
const std::string & detector_model_path,
const std::string & super_resolution_prototxt_path,
const std::string & super_resolution_caffe_model_path) {
p = cv::makePtr<NNDetector::Impl>();
if (!detector_config_path.empty() && !detector_model_path.empty()) {
p->detector_ = std::make_shared<YoloWrapper>();
p->detector_->init(detector_config_path, detector_model_path);
}
else {
p->detector_ = NULL;
}
//TODO:初始化超分辨率图像模型
if (!super_resolution_prototxt_path.empty() && !super_resolution_caffe_model_path.empty()) {
p->super_resolution_model_ = std::make_shared<SuperScale>();
p->super_resolution_model_->init(super_resolution_prototxt_path, super_resolution_caffe_model_path);
}
else {
p->super_resolution_model_ = NULL;
}
}
std::vector<cv::Mat> NNDetector::getScaleMap(cv::InputArray img) {
auto scale_list = p->getScaleList(img.cols(), img.rows());
auto scaleMat = std::vector<cv::Mat>();
for (auto cur_scale : scale_list) {
cv::Mat scaled = p->super_resolution_model_->processImageScale(img.getMat(), cur_scale, true);
scaleMat.push_back(scaled);
}
return scaleMat;
}
std::vector<cv::Mat> NNDetector::detect(cv::InputArray img, std::vector<cv::Rect> &points) {
CV_Assert(!img.empty());
if (img.cols() <= 20 || img.rows() <= 20) {
return std::vector<cv::Mat>();
}
cv::Mat input;
int incn = img.channels();
if (incn == 4) {
cv::cvtColor(img, input, cv::COLOR_BGRA2BGR);
}
else if (incn == 1) {
cv::cvtColor(img, input, cv::COLOR_GRAY2BGR);//只支持三通道彩色图
}
else {
input = img.getMat();
}
std::vector<cv::Rect> bboxes = p->detect(input);
//限定框,防止越界
cv::Mat candiMat;
cv::Rect limit(0, 0, input.cols, input.rows);
//因为可能不准,故box会往外扩充
std::vector<cv::Mat> candidate;
for (std::vector<cv::Rect>::iterator it = bboxes.begin(); it != bboxes.end(); ++it) {
cv::Rect bbox = (*it);
int minSize = cv::min(bbox.width, bbox.height) / 2;
candiMat = input(cv::Rect(cv::Point2i(bbox.tl().x - minSize / 2, bbox.tl().y - minSize / 2), cv::Point(bbox.br().x + minSize / 2, bbox.br().y + minSize / 2))&limit);
candidate.push_back(candiMat);
points.push_back(cv::Rect(cv::Point2i(bbox.tl().x - minSize / 2, bbox.tl().y - minSize / 2), cv::Point(bbox.br().x + minSize / 2, bbox.br().y + minSize / 2))&limit);
}
return candidate;
}
std::vector<cv::Rect> NNDetector::Impl::detect(const cv::Mat& img) {
cv::Mat input;
resize(img, input, cv::Size(img.cols / 2, img.rows / 2), 0, 0, cv::INTER_CUBIC);//因为训练使用缩放一半的图
return detector_->forward(img);
}
std::vector<float> NNDetector::Impl::getScaleList(const int width, const int height) {
if (width < 320 || height < 320) return{ 1.0, 2.0, 0.5 };
if (width < 640 && height < 640) return{ 1.0, 0.5 };
return{ 0.5, 1.0 };
}
#pragma once
//
// objectDetection¡¤±êÍ·
//
#ifndef __OBJECTDETECTION_H
#define __OBJECTDETECTION_H
#include "opencv2/core.hpp"
class NNDetector {
public:
NNDetector(const std::string& detector_config_path = "",
const std::string& detector_model_path = "",
const std::string& super_resolution_config_path = "",
const std::string& super_resolution_model_path = "");
NNDetector() {};
std::vector<cv::Mat> detect(cv::InputArray img,
std::vector<cv::Rect> &points = std::vector<cv::Rect>());
std::vector<cv::Mat> getScaleMap(cv::InputArray img);
protected:
class Impl;
cv::Ptr<Impl> p;
};
#endif/* __OBJECTDETECTION_H */
#include "ssd_detector.h"
#define CLIP(x, x1, x2) cv::max(x1, cv::min(x, x2))
namespace wechat_qrcode {
int SSDDetector::init(const std::string& proto_path, const std::string& model_path) {
net_ = cv::dnn::readNetFromCaffe(proto_path, model_path);
return 0;
}
std::vector<cv::Mat> SSDDetector::forward(cv::Mat img, const int target_width, const int target_height) {
int img_w = img.cols;
int img_h = img.rows;
cv::Mat input;
resize(img, input, cv::Size(target_width, target_height), 0, 0, cv::INTER_CUBIC);
cv::dnn::blobFromImage(input, input, 1.0 / 255, cv::Size(input.cols, input.rows), { 0.0f, 0.0f, 0.0f },
false, false);
net_.setInput(input, "data");
auto prob = net_.forward("detection_output");
std::vector<cv::Mat> point_list;
// the shape is (1,1,100,7)=>(batch,channel,count,dim)
for (int row = 0; row < prob.size[2]; row++) {
const float* prob_score = prob.ptr<float>(0, 0, row);
// prob_score[0] is not used.
// prob_score[1]==1 stands for qrcode
if (prob_score[1] == 1 && prob_score[2] > 1E-5) {
// add a safe score threshold due to https://github.com/opencv/opencv_contrib/issues/2877
// prob_score[2] is the probability of the qrcode, which is not used.
auto point = cv::Mat(4, 2, CV_32FC1);
float x0 = CLIP(prob_score[3] * img_w, 0.0f, img_w - 1.0f);
float y0 = CLIP(prob_score[4] * img_h, 0.0f, img_h - 1.0f);
float x1 = CLIP(prob_score[5] * img_w, 0.0f, img_w - 1.0f);
float y1 = CLIP(prob_score[6] * img_h, 0.0f, img_h - 1.0f);
point.at<float>(0, 0) = x0;
point.at<float>(0, 1) = y0;
point.at<float>(1, 0) = x1;
point.at<float>(1, 1) = y0;
point.at<float>(2, 0) = x1;
point.at<float>(2, 1) = y1;
point.at<float>(3, 0) = x0;
point.at<float>(3, 1) = y1;
point_list.push_back(point);
}
}
return point_list;
}
}
\ No newline at end of file \ No newline at end of file
#ifndef __DETECTOR_SSD_DETECTOR_HPP_
#define __DETECTOR_SSD_DETECTOR_HPP_
#include <stdio.h>
#include "opencv2/dnn.hpp"
#include "opencv2/imgproc.hpp"
namespace wechat_qrcode {
class SSDDetector {
public:
SSDDetector() {};
~SSDDetector() {};
int init(const std::string& proto_path, const std::string& model_path);
std::vector<cv::Mat> forward(cv::Mat img, const int target_width, const int target_height);
private:
cv::dnn::Net net_;
};
}
#endif // __DETECTOR_SSD_DETECTOR_HPP_
#include "super_scale.h" #include "superScale.h"
#define CLIP(x, x1, x2) cv::max(x1, cv::min(x, x2)) #define CLIP(x, x1, x2) cv::max(x1, cv::min(x, x2))
namespace wechat_qrcode { int SuperScale::init(const std::string &proto_path, const std::string &model_path) {
int SuperScale::init(const std::string &proto_path, const std::string &model_path) {
srnet_ = cv::dnn::readNetFromCaffe(proto_path, model_path); srnet_ = cv::dnn::readNetFromCaffe(proto_path, model_path);
net_loaded_ = true; net_loaded_ = true;
return 0; return 0;
} }
cv::Mat SuperScale::processImageScale(const cv::Mat &src, float scale, const bool &use_sr, cv::Mat SuperScale::processImageScale(const cv::Mat &src, float scale, const bool &use_sr,
int sr_max_size) { int sr_max_size) {
cv::Mat dst = src; cv::Mat dst = src;
if (scale == 1.0) { // src if (scale == 1.0) { // src
...@@ -34,9 +32,9 @@ namespace wechat_qrcode { ...@@ -34,9 +32,9 @@ namespace wechat_qrcode {
} }
return dst; return dst;
} }
int SuperScale::superResoutionScale(const cv::Mat &src, cv::Mat &dst) { int SuperScale::superResoutionScale(const cv::Mat &src, cv::Mat &dst) {
cv::Mat blob; cv::Mat blob;
cv::dnn::blobFromImage(src, blob, 1.0 / 255, cv::Size(src.cols, src.rows), { 0.0f }, false, false); cv::dnn::blobFromImage(src, blob, 1.0 / 255, cv::Size(src.cols, src.rows), { 0.0f }, false, false);
...@@ -53,5 +51,4 @@ namespace wechat_qrcode { ...@@ -53,5 +51,4 @@ namespace wechat_qrcode {
} }
} }
return 0; return 0;
}
} // namespace wechat_qrcode
\ No newline at end of file \ No newline at end of file
}
\ No newline at end of file \ No newline at end of file
#ifndef __SCALE_SUPER_SCALE_HPP_ #ifndef __SCALE_SUPER_SCALE_H_
#define __SCALE_SUPER_SCALE_HPP_ #define __SCALE_SUPER_SCALE_H_
#include <stdio.h> #include <stdio.h>
#include "opencv2/dnn.hpp" #include "opencv2/dnn.hpp"
#include "opencv2/imgproc.hpp" #include "opencv2/imgproc.hpp"
namespace wechat_qrcode { class SuperScale {
class SuperScale { public:
public:
SuperScale() {}; SuperScale() {};
~SuperScale() {}; ~SuperScale() {};
int init(const std::string &proto_path, const std::string &model_path); int init(const std::string &proto_path, const std::string &model_path);
cv::Mat processImageScale(const cv::Mat &src, float scale, const bool &use_sr, int sr_max_size = 160); cv::Mat processImageScale(const cv::Mat &src, float scale, const bool &use_sr, int sr_max_size = 160);
private: private:
cv::dnn::Net srnet_; cv::dnn::Net srnet_;
bool net_loaded_ = false; bool net_loaded_ = false;
int superResoutionScale(const cv::Mat &src, cv::Mat &dst); int superResoutionScale(const cv::Mat &src, cv::Mat &dst);
}; };
} // namespace wechat_qrcode
#endif // __SCALE_SUPER_SCALE_HPP_
\ No newline at end of file \ No newline at end of file
#endif // __SCALE_SUPER_SCALE_H_
#include "wechat_qrcode.h"
#include "align.h"
#include "ssd_detector.h"
#include "super_scale.h"
namespace wechat_qrcode {
class WeChatQRCode::Impl {
public:
Impl() {}
~Impl() {}
/**
* @brief detect QR codes from the given image
*
* @param img supports grayscale or color (BGR) image.
* @return vector<Mat> detected QR code bounding boxes.
*/
std::vector<cv::Mat> detect(const cv::Mat& img);
/**
* @brief decode QR codes from detected points
*
* @param img supports grayscale or color (BGR) image.
* @param candidate_points detected points. we name it "candidate points" which means no
* all the qrcode can be decoded.
* @param points succussfully decoded qrcode with bounding box points.
* @return vector<string>
*/
std::vector<std::string> decode(const cv::Mat& img, std::vector<cv::Mat>& candidate_points,
std::vector<cv::Mat>& points);
int applyDetector(const cv::Mat& img, std::vector<cv::Mat>& points);
cv::Mat cropObj(const cv::Mat& img, const cv::Mat& point, Align& aligner);
std::vector<float> getScaleList(const int width, const int height);
std::shared_ptr<SSDDetector> detector_;
std::shared_ptr<SuperScale> super_resolution_model_;
bool use_nn_detector_, use_nn_sr_;
};
WeChatQRCode::WeChatQRCode(const cv::String& detector_prototxt_path,
const cv::String& detector_caffe_model_path,
const cv::String& super_resolution_prototxt_path,
const cv::String& super_resolution_caffe_model_path) {
p = cv::makePtr<WeChatQRCode::Impl>();
if (!detector_caffe_model_path.empty() && !detector_prototxt_path.empty()) {
// initialize detector model (caffe)
p->use_nn_detector_ = true;
p->detector_ = std::make_shared<SSDDetector>();
auto ret = p->detector_->init(detector_prototxt_path, detector_caffe_model_path);
CV_Assert(ret == 0);
}
else {
p->use_nn_detector_ = false;
p->detector_ = NULL;
}
// initialize super_resolution_model
// it could also support non model weights by cubic resizing
// so, we initialize it first.
p->super_resolution_model_ = std::make_shared<SuperScale>();
if (!super_resolution_prototxt_path.empty() && !super_resolution_caffe_model_path.empty()) {
p->use_nn_sr_ = true;
// initialize dnn model (caffe format)
auto ret = p->super_resolution_model_->init(super_resolution_prototxt_path,
super_resolution_caffe_model_path);
CV_Assert(ret == 0);
}
else {
p->use_nn_sr_ = false;
}
}
std::vector<std::string> WeChatQRCode::detectAndDecode(cv::InputArray img, cv::OutputArrayOfArrays points) {
CV_Assert(!img.empty());
CV_CheckDepthEQ(img.depth(), CV_8U, "");
if (img.cols() <= 20 || img.rows() <= 20) {
return std::vector<std::string>(); // image data is not enough for providing reliable results
}
cv::Mat input_img;
int incn = img.channels();
CV_Check(incn, incn == 1 || incn == 3 || incn == 4, "");
if (incn == 3 || incn == 4) {
cvtColor(img, input_img, cv::COLOR_BGR2GRAY);
}
else {
input_img = img.getMat();
}
auto candidate_points = p->detect(input_img);
auto res_points = std::vector<cv::Mat>();
auto ret = p->decode(input_img, candidate_points, res_points);
// opencv type convert
std::vector<cv::Mat> tmp_points;
if (points.needed()) {
for (size_t i = 0; i < res_points.size(); i++) {
cv::Mat tmp_point;
tmp_points.push_back(tmp_point);
res_points[i].convertTo(((cv::OutputArray)tmp_points[i]), CV_32FC2);
}
points.createSameSize(tmp_points, CV_32FC2);
points.assign(tmp_points);
}
return ret;
};
std::vector<std::string> WeChatQRCode::Impl::decode(const cv::Mat& img, std::vector<cv::Mat>& candidate_points,
std::vector<cv::Mat>& points) {
if (candidate_points.size() == 0) {
return std::vector<std::string>();
}
std::vector<std::string> decode_results;
for (auto& point : candidate_points) {
cv::Mat cropped_img;
if (use_nn_detector_) {
Align aligner;
cropped_img = cropObj(img, point, aligner);
}
else {
cropped_img = img;
}
// scale_list contains different scale ratios
auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows);
for (auto cur_scale : scale_list) {
cv::Mat scaled_img =
super_resolution_model_->processImageScale(cropped_img, cur_scale, use_nn_sr_);
std::string result;
//DecoderMgr decodemgr;
//auto ret = decodemgr.decodeImage(scaled_img, use_nn_detector_, result);
//if (ret == 0) {
// decode_results.push_back(result);
// points.push_back(point);
// break;
//}
}
}
return decode_results;
}
std::vector<cv::Mat> WeChatQRCode::Impl::detect(const cv::Mat& img) {
auto points = std::vector<cv::Mat>();
if (use_nn_detector_) {
// use cnn detector
auto ret = applyDetector(img, points);
CV_Assert(ret == 0);
}
else {
auto width = img.cols, height = img.rows;
// if there is no detector, use the full image as input
auto point = cv::Mat(4, 2, CV_32FC1);
point.at<float>(0, 0) = 0.0f;
point.at<float>(0, 1) = 0.0f;
point.at<float>(1, 0) = float(width - 1);
point.at<float>(1, 1) = 0.0f;
point.at<float>(2, 0) = float(width - 1);
point.at<float>(2, 1) = float(height - 1);
point.at<float>(3, 0) = 0.0f;
point.at<float>(3, 1) = float(height - 1);
points.push_back(point);
}
return points;
}
int WeChatQRCode::Impl::applyDetector(const cv::Mat& img, std::vector<cv::Mat>& points) {
int img_w = img.cols;
int img_h = img.rows;
// hard code input size
int minInputSize = 400;
float resizeRatio = (float)sqrt(img_w * img_h * 1.0 / (minInputSize * minInputSize));
int detect_width = cvRound((float)img_w / resizeRatio);
int detect_height = cvRound((float)img_h / resizeRatio);
points = detector_->forward(img, detect_width, detect_height);
return 0;
}
cv::Mat WeChatQRCode::Impl::cropObj(const cv::Mat& img, const cv::Mat& point, Align& aligner) {
// make some padding to boost the qrcode details recall.
float padding_w = 0.1f, padding_h = 0.1f;
auto min_padding = 15;
auto cropped = aligner.crop(img, point, padding_w, padding_h, min_padding);
return cropped;
}
// empirical rules
std::vector<float> WeChatQRCode::Impl::getScaleList(const int width, const int height) {
if (width < 320 || height < 320) return{ 1.0, 2.0, 0.5 };
if (width < 640 && height < 640) return{ 1.0, 0.5 };
return{ 0.5, 1.0 };
}
} // namespace wechat_qrcode
\ No newline at end of file \ No newline at end of file
#pragma once
//
// eyemSmoothͷ
//
#ifndef __OPENCV_WECHAT_QRCODE_HPP__
#define __OPENCV_WECHAT_QRCODE_HPP__
#define CLIP(x, x1, x2) cv::max(x1, cv::min(x, x2))
#include "opencv2/core.hpp"
namespace wechat_qrcode {
class WeChatQRCode {
public:
WeChatQRCode(const std::string& detector_prototxt_path = "",
const std::string& detector_caffe_model_path = "",
const std::string& super_resolution_prototxt_path = "",
const std::string& super_resolution_caffe_model_path = "");
~WeChatQRCode() {};
std::vector<std::string> detectAndDecode(cv::InputArray img,
cv::OutputArrayOfArrays points = cv::noArray());
protected:
class Impl;
cv::Ptr<Impl> p;
};
} // namespace wechat_qrcode
#endif/* __OPENCV_WECHAT_QRCODE_HPP__ */
\ No newline at end of file \ No newline at end of file
#include "yoloWrapper.h"
int YoloWrapper::init(const cv::String& detector_config_path,
const cv::String& detector_model_path) {
if (!detector_config_path.empty() && !detector_model_path.empty()) {
//加载并初始化网络
net_ = cv::dnn::readNet(detector_config_path, detector_model_path);
net_.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net_.setPreferableBackend(cv::dnn::DNN_TARGET_CPU);
}
return 0;
}
std::vector<cv::Rect> YoloWrapper::forward(cv::Mat img) {
//获取输出层名称
auto layerNames = net_.getLayerNames();
std::vector<int> outLayers = net_.getUnconnectedOutLayers();
std::vector<std::string> outBlobNames(outLayers.size());
for (int i = 0; i < outLayers.size(); i++) {
outBlobNames[i] = layerNames[outLayers[i] - 1];
}
//预处理图像
cv::Mat blob;
cv::dnn::blobFromImage(img, blob, 1 / 255., cv::Size(608, 608));
//为网络输入新值
net_.setInput(blob);
//获取预测结果
std::vector<cv::Mat> outputBlobs;
net_.forward(outputBlobs, outBlobNames);
std::vector<float> confidences;
std::vector<cv::Rect> bboxes;
for (int n = 0; n < outputBlobs.size(); n++) {
for (int row = 0; row < outputBlobs[n].rows; row++) {
//置信度
cv::Mat prob = outputBlobs[n](cv::Range(row, row + 1), cv::Range(5, outputBlobs[n].cols));
double confidence;
cv::Point classIdPoint;
//取得最大分数值与索引
cv::minMaxLoc(prob, 0, &confidence, 0, &classIdPoint);
//把可能的区域都算作进去
if (confidence > 0.01) {
cv::Mat dt = outputBlobs[n](cv::Range(row, row + 1), cv::Range(0, 5));
int cx = cvRound(dt.ptr<float>(0)[0] * (float)img.cols);
int cy = cvRound(dt.ptr<float>(0)[1] * (float)img.rows);
int w = cvRound(dt.ptr<float>(0)[2] * (float)img.cols);
int h = cvRound(dt.ptr<float>(0)[3] * (float)img.rows);
int left = cx - w / 2;
int top = cy - h / 2;
confidences.push_back((float)confidence);
bboxes.push_back(cv::Rect(left, top, w, h));
}
}
}
std::vector<int> indices;
//非极大值抑制
cv::dnn::NMSBoxes(bboxes, confidences, 0.01, 0.05, indices);
//裁剪区域
auto points = std::vector<cv::Rect>();
for (int i = 0; i < indices.size(); i++) {
int idx = indices[i];
cv::Rect bbox = bboxes[idx] & cv::Rect(0, 0, img.cols, img.rows);
points.push_back(bbox);
}
return points;
}
\ No newline at end of file \ No newline at end of file
#pragma once
//
// yoloWrapperͷ
//
#ifndef __YOLOWRAPPER_H
#define __YOLOWRAPPER_H
#include "opencv2/dnn.hpp"
#include "opencv2/imgproc.hpp"
class YoloWrapper
{
public:
YoloWrapper() {};
~YoloWrapper() {};
int init(const std::string& config_path, const std::string& model_path);
std::vector<cv::Rect> forward(cv::Mat img);
private:
cv::dnn::Net net_;
};
#endif/* __YOLOWRAPPER_H */
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!