前面两篇文章已经将包装袋日期识别的功能基本实现,接下来将介绍在vs2017平台上将OpenCV与Halclass="superseo">con联合编程。
首先,需要在vs上配置好OpenCV与Halcon,配置问题,有许多博主已经发表过了,这里不再赘述。
OpenCV与Halcon联合编程主要解决的问题是数据类型转换。OpenCV的图片数据类型为Mat,Halcon的图片数据类型为HObject。Halcon的HObject类型并不能全部转换为Mat,只有image类型的可以转换为Mat。
下面为Mat与HObject相互转换的代码:
//HObject转Mat
cv::Mat HImageToMat(HalconCpp::HObject &H_img)
{
cv::Mat cv_img;
HalconCpp::HTuple channels, w, h;
HalconCpp::ConvertImageType(H_img, &H_img, "byte");
HalconCpp::CountChannels(H_img, &channels);
if (channels.I() == 1)
{
HalconCpp::HTuple pointer;
GetImagePointer1(H_img, &pointer, nullptr, &w, &h);
int width = w.I(), height = h.I();
int size = width * height;
cv_img = cv::Mat::zeros(height, width, CV_8UC1);
memcpy(cv_img.data, (void*)(pointer.L()), size);
}
else if (channels.I() == 3)
{
HalconCpp::HTuple pointerR, pointerG, pointerB;
HalconCpp::GetImagePointer3(H_img, &pointerR, &pointerG, &pointerB, nullptr, &w, &h);
int width = w.I(), height = h.I();
int size = width * height;
cv_img = cv::Mat::zeros(height, width, CV_8UC3);
uchar* R = (uchar*)(pointerR.L());
uchar* G = (uchar*)(pointerG.L());
uchar* B = (uchar*)(pointerB.L());
for (int i = 0; i < height; ++i)
{
uchar *p = cv_img.ptr(i);
for (int j = 0; j < width; ++j)
{
p[3 * j] = B[i * width + j];
p[3 * j + 1] = G[i * width + j];
p[3 * j + 2] = R[i * width + j];
}
}
}
return cv_img;
}
//Mat转HObject
HalconCpp::HObject MatToHImage(cv::Mat& cv_img)
{
HalconCpp::HObject H_img;
if (cv_img.channels() == 1)
{
int height = cv_img.rows, width = cv_img.cols;
int size = height * width;
uchar *temp = new uchar[size];
memcpy(temp, cv_img.data, size);
HalconCpp::GenImage1(&H_img, "byte", width, height, (Hlong)(temp));
delete[] temp;
}
else if (cv_img.channels() == 3)
{
int height = cv_img.rows, width = cv_img.cols;
int size = height * width;
uchar *B = new uchar[size];
uchar *G = new uchar[size];
uchar *R = new uchar[size];
for (int i = 0; i < height; i++)
{
uchar *p = cv_img.ptr(i);
for (int j = 0; j < width; j++)
{
B[i * width + j] = p[3 * j];
G[i * width + j] = p[3 * j + 1];
R[i * width + j] = p[3 * j + 2];
}
}
HalconCpp::GenImage3(&H_img, "byte", width, height, (Hlong)(R), (Hlong)(G), (Hlong)(B));
delete[] R;
delete[] G;
delete[] B;
}
return H_img;
}
下面代码是我整合后的:
#include
#include
#include
#include "HalconCpp.h"
#include "HDevThread.h"
using namespace std;
using namespace cv;
using namespace HalconCpp;
//数据转换
cv::Mat HImageToMat(HalconCpp::HObject &H_img)
{
cv::Mat cv_img;
HalconCpp::HTuple channels, w, h;
HalconCpp::ConvertImageType(H_img, &H_img, "byte");
HalconCpp::CountChannels(H_img, &channels);
if (channels.I() == 1)
{
HalconCpp::HTuple pointer;
GetImagePointer1(H_img, &pointer, nullptr, &w, &h);
int width = w.I(), height = h.I();
int size = width * height;
cv_img = cv::Mat::zeros(height, width, CV_8UC1);
memcpy(cv_img.data, (void*)(pointer.L()), size);
}
else if (channels.I() == 3)
{
HalconCpp::HTuple pointerR, pointerG, pointerB;
HalconCpp::GetImagePointer3(H_img, &pointerR, &pointerG, &pointerB, nullptr, &w, &h);
int width = w.I(), height = h.I();
int size = width * height;
cv_img = cv::Mat::zeros(height, width, CV_8UC3);
uchar* R = (uchar*)(pointerR.L());
uchar* G = (uchar*)(pointerG.L());
uchar* B = (uchar*)(pointerB.L());
for (int i = 0; i < height; ++i)
{
uchar *p = cv_img.ptr(i);
for (int j = 0; j < width; ++j)
{
p[3 * j] = B[i * width + j];
p[3 * j + 1] = G[i * width + j];
p[3 * j + 2] = R[i * width + j];
}
}
}
return cv_img;
}
// Main procedure
void action(HalconCpp::HImage H_img_new, Mat img)//导出Halcon后需要修改的地方
{
// Local iconic variables
HObject ho_Image01, ho_ImggrayInvert, ho_Region;
HObject ho_ConnectedRegions, ho_SelectedRegions, ho_SortedRegions;
HObject ho_RegionTrans, ho_ObjectSelected;
// Local control variables
HTuple hv_Width, hv_Height, hv_Area, hv_Row;
HTuple hv_Column, hv_MeanRow, hv_Number, hv_OCRHandle;
HTuple hv_I, hv_Class, hv_Confidence, hv_ocrNumbers, hv_Array1;
HTuple hv_Equal;
// dev_update_window(...); only in hdevelop
// ReadImage(&ho_Image01, "C:/Users/86133/source/repos/main/main/01.jpg");
GetImageSize(H_img_new, &hv_Width, &hv_Height);
InvertImage(H_img_new, &ho_ImggrayInvert);
Threshold(H_img_new, &ho_Region, 130, 600);
Connection(ho_Region, &ho_ConnectedRegions);
SelectShape(ho_ConnectedRegions, &ho_SelectedRegions, "area", "and", 50, 500);
SortRegion(ho_SelectedRegions, &ho_SortedRegions, "first_point", "true", "column");
ShapeTrans(ho_SortedRegions, &ho_RegionTrans, "rectangle1");
AreaCenter(ho_RegionTrans, &hv_Area, &hv_Row, &hv_Column);
hv_MeanRow = hv_Row.TupleMean();
CountObj(ho_SortedRegions, &hv_Number);
ReadOcrClassMlp(//'C:/Users/86133/Desktop/学习资料/halcon/1.omc'
"C:/Users/86133/Desktop/17707217/halcon/1.omc",
&hv_OCRHandle);
{
HTuple end_val15 = hv_Number;
HTuple step_val15 = 1;
for (hv_I = 1; hv_I.Continue(end_val15, step_val15); hv_I += step_val15)
{
SelectObj(ho_SortedRegions, &ho_ObjectSelected, hv_I);
DoOcrSingleClassMlp(ho_ObjectSelected, ho_ImggrayInvert, hv_OCRHandle, 1, &hv_Class,
&hv_Confidence);
if (HDevWindowStack::IsOpen())
ClearWindow(HDevWindowStack::GetActive());
if (HDevWindowStack::IsOpen())
DispObj(ho_ObjectSelected, HDevWindowStack::GetActive());
cout << (HString)hv_Class;
hv_ocrNumbers[hv_I - 1] = hv_Class;
hv_Array1.Clear();
hv_Array1[0] = "2";
hv_Array1[1] = "0";
hv_Array1[2] = "2";
hv_Array1[3] = "1";
hv_Array1[4] = "/";
hv_Array1[5] = "0";
hv_Array1[6] = "5";
hv_Array1[7] = "/";
hv_Array1[8] = "2";
hv_Array1[9] = "3";
hv_Array1[10] = "/";
hv_Array1[11] = "A";
hv_Array1[12] = "-";
hv_Array1[13] = "Y";
TupleEqual(hv_Array1, hv_ocrNumbers, &hv_Equal);
}
cout << endl;
//判断日期是否正确,正确则在原图上打印“OK”,否则打印“NO”
if (hv_Equal == 1) {
cout << "1" << endl;
putText(img, "OK", Point(50, 50), FONT_HERSHEY_COMPLEX_SMALL, 2, Scalar(255, 69, 255), 2);
}
else if (hv_Equal == 0) {
cout << "0" << endl;
putText(img, "NO", Point(50, 50), FONT_HERSHEY_COMPLEX_SMALL, 2, Scalar(255, 69, 255), 2);
}
}
}
#ifndef NO_EXPORT_APP_MAIN
#endif
int main()
{
int ret = 0;
Mat img = imread("C:\Users\Public\Pictures\baozhuang03.jpg");
//imshow("test", img);
Mat imgGray, imgBlur, imgCanny, imgDil, imgErode, imgSobel, close;
//图像预处理
cvtColor(img, imgGray, COLOR_BGR2RGBA);
GaussianBlur(imgGray, imgBlur, Size(5, 5), 5, 0);
threshold(imgBlur, imgBlur, 130, 255,THRESH_BINARY );
Mat kernel = getStructuringElement(0, Size(35, 35));
morphologyEx(imgBlur, close, MORPH_CLOSE, kernel);
Canny(close, imgCanny, 30, 30);
Mat kernel2 = getStructuringElement(0, Size(5, 5));
dilate(imgCanny, imgDil, kernel2);
//找轮廓
vector>contours;
vectorhierarchy;
findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//drawContours(img, contours, -1, Scalar(0, 255, 0), 2);
int exitArea=0;//判断是否存在可检测的目标
for (int i = 0; i < contours.size(); i++) {
int area = contourArea(contours[i]);
//cout << area << endl;
vector>conPoly(contours.size());
vectorboundRect(contours.size());
string objectType;
if (area > 14000 && area < 15000) {
float peri = arcLength(contours[i], true);
approxPolyDP(contours[i], conPoly[i], 0.02*peri, true);
RotatedRect rrect = minAreaRect(conPoly[i]);
Point2f points[4];
rrect.points(points);
Point2f cpt = rrect.center;
for (int i = 0; i < 4; i++) {
if (i == 3)
{
line(img, points[i], points[0], Scalar(0, 255, 0), 1, 8, 0);
break;
}
line(img, points[i], points[i + 1], Scalar(0, 255, 0), 1, 8, 0);
}
imshow("imgArea", img);
//反射变换
float w = 500, h = 40;
Mat matrix, imgWarp;
Point2f src[4] = { points[0],points[1],points[3],points[2] };
Point2f dst[4] = { {0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h} };
matrix = getPerspectiveTransform(src, dst);
warpPerspective(img, imgWarp, matrix, Point(w, h));
flip(imgWarp, imgWarp, -1);
imshow("Image Warp", imgWarp);
//imwrite("01.jpg", imgWarp);
HalconCpp::HImage H_img_new = MatToHImage(imgWarp); //图像类型转换
try
{
#if defined(_WIN32)
SetSystem("use_window_thread", "true");
#elif defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
XInitThreads();
#endif
SetHcppInterfaceStringEncodingIsUtf8(false);
// Default settings used in HDevelop (can be omitted)
SetSystem("width", 512);
SetSystem("height", 512);
#ifndef __APPLE__
action(H_img_new,img);//Halcon导出后需修改的地方
#else
ret = apple_main(argc, argv);
#endif
}
catch (HException &exception)
{
fprintf(stderr, " Error #%u in %s: %s\n", exception.ErrorCode(),
(const char *)exception.ProcName(),
(const char *)exception.ErrorMessage());
ret = 1;
}
exitArea = 1;
}
}
if (exitArea == 0)
{
putText(img, "NO", Point(50, 50), FONT_HERSHEY_COMPLEX_SMALL, 2, Scalar(255,
69, 255), 2);
}
imshow("轮廓检测", img);
waitKey(0);
system("pause");
return ret;
}
#endif
最终展示结果
下图为日期错误样例 ,因为目标区域的面积与我们所规定的不一致,所以并没有进行ocr检测。即使检测了,相信也是会判断为错误的。
总结:
该包装袋的日期检测案例所受环境因素影响较多,比如,包装袋的颜色、材质、打光位置等因素都会导致程序不能很好的定位到目标位置。所以该程序只适用于特定场景检测。
最好,希望我的分享能对大家有1..帮助,若存在什么问题,欢迎各位友善提出。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)