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

前面两篇文章已经将包装袋日期识别的功能基本实现,接下来将介绍在vs2017平台上将OpenCV与Halcon联合编程。

 

首先,需要在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<uchar>(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<uchar>(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<iostream>
#include<opencv2/opencv.hpp>
#include<vector>
#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<uchar>(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/\321\247\317\260\327\312\301\317/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<vector<Point>>contours;
	vector<Vec4i>hierarchy;

	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<vector<Point>>conPoly(contours.size());
		vector<Rect>boundRect(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..帮助,若存在什么问题,欢迎各位友善提出。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: win10+vs2017+qt+opencv 是一种常用的开发环境组合,可以用于开发图像处理、计算机视觉等应用程序。其中,win10 是操作系统,vs2017 是集成开发环境,qt 是跨平台应用程序开发框架,opencv 是计算机视觉库。这种组合可以提高开发效率,简化开发流程,同时也具有良好的兼容性和稳定性。 ### 回答2: Win10 vs2017 Qt OpenCV,其实是个不同的对象,下面将它们逐一进行分析。 Win10,顾名思义,就是Windows 10操作系统的缩写。Windows是全球最为知名的操作系统之一,其在操作界面、软件支持、硬件厂商等方面具有较为广泛的应用和覆盖。Win10更是在基础操作系统的基础上,对界面、安全性、易用性、兼容性等方面进行了优化和改善,使其成为一个更为齐全且更易于使用的操作系统,目前得到了广泛的用户认可。 Vs2017,是Visual Studio的缩写,2017表示该版本发布的年份。Vs是由美国微软公司开发的一款用于软件开发的集成开发环境。Vs不仅包含了代码编写、调试、编译等方面的工具,还提供了一系列辅助开发技术,例如代码重构、版本管理、跨平台开发等等。Vs被广泛应用于Windows平台下的开发,除此之外也支持其他操作系统、开发语言以及开发模式等等,其本身也在持续地更新升级以适应日益变化的开发环境。 Qt,是一个跨平台的C++应用程序开发框架,也被称为“跨平台图形用户界面应用程序开发框架”。Qt是由挪威Trolltech公司于1991年开始开发的,旨在为开发人员提供高效的框架,并能够快速构建新的应用程序。Qt具有良好的可扩展性并提供丰富的开发API,使得其可以被用于开发桌面应用、移动应用、嵌入式应用等等。在跨平台方面,Qt提供了大量的平台支持,例如Windows、Linux、macOS、Android、iOS等等,极大地方便了开发人员的工作。 OpenCV,全称是“开源计算机视觉库”,是一套基于BSD许可协议的跨平台计算机视觉应用程序开发库,可用于开发实时的计算机视觉应用程序。该库广泛应用于学术研究、科研领域以及商业领域,其支持的领域也很广泛,例如目标检测、图像处理、运动跟踪、机器学习等等。OpenCV支持众多编程语言,例如C++、Python、Java等等,也可以被用于多种操作系统上,例如Windows、Linux、macOS等等。 从以上几个对象的简介来看,Win10、Vs2017、Qt、OpenCV分别是一款操作系统、一个开发工具、一个应用框架和一个开发库。它们是在不同的层面上为开发者和用户提供更好的工具和服务,目的是为了更好地完成软件开发的工作。不过在这些工具之间使用并不是互相排斥的,有时候我们也需要使用它们的组合,以便于完成某些特定的开发任务。 ### 回答3: Win10 VS2017 QT OpenCV是现今非常热门的开发环境,被广泛用于开发图形图像领域。 Win10是目前Microsoft推出的最新的操作系统,与之前的操作系统相比,更加注重用户体验,同时也更注重安全性和稳定性。Win10的更新速度很快,对开发环境与软件的兼容性比之前的版本都要更好。 VS2017是Microsoft推出的最新的开发IDE,它更加注重与异构工具链、云开发的集成,提高了团队合作的效率,同时提供了许多新的代码分析和调试工具,能够更准确地定位出现的错误。此外,VS2017也提供了用于跨平台开发的工具,非常适用于在Win10系统上进行开发。 QT是一个跨平台的C++开发框架, 其提供了丰富的GUI类库和工具。QT的特点是:跨平台,简单易用,一致性强,可定制化程度高。QT是一款免费的开源软件,因此十分受欢迎。在Win10系统上使用QT进行开发,可以帮助开发者快速地编写GUI应用程序。 OpenCV是一款流行的计算机视觉库,它提供了许多图像和视频处理的函数和算法。OpenCV可用于各大平台的开发,操作方便而深受开发者的青睐。OpenCV适用于Win10系统上,可以在QT环境中使用,为开发者提供优雅高效的图像处理解决方案。 综上所述,在Win10系统中,使用VS2017作为开发IDE,配合QT进行GUI界面的实现OpenCV进行计算机视觉处理,能够快速地搭建起强大的开发环境。Win10 VS2017 QT OpenCV的组合能够提高开发者的效率与开发程序的稳定性,并应用于图形图像领域的快速开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值