VS2017+OpenCV+Halcon实现包装袋日期识别(三)——数据转换(整合)

VS2017+OpenCV+Halcon实现包装袋日期识别(三)——数据转换(整合),第1张

前面两篇文章已经将包装袋日期识别的功能基本实现,接下来将介绍在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..帮助,若存在什么问题,欢迎各位友善提出。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/719360.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存