zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++ 下 Halcon 与 OpenCV 图像的转换

OpencvC++转换 图像 HALCON
2023-06-13 09:18:40 时间

Halcon 中的图像数据结构为 HImage, OpenCV 中的图像为 Mat,使用中经常需要相互转换的情况,本文记录转换方式。

转换规则

halcon、opencv 和 C++图像内存数据处理机制有差异,在进行相互转换的时候需要注意内存数据排列问题,否则可能出现花图或者多出黑边等现象。

  • Halcon 的 HImage 和 OpenCV 的 Mat 都是连续存储图像数据的,HImage 存储数据是每个通道的数据存在一起的, Mat 的数据是一个像素点中的多个通道数据连续存在一起的。
  • 单通道图像如果位深度一致可以直接复制内存,如果多通道则需要按照图像的存储规则重新整理。

HImage to Mat

8 bit 深度图像

  • 当图像为 8 bit 单通道普通图像时,Mat 图像在内存中各个像素连续排列,像素存在的顺序和 HImage 一致,可以直接拷贝内存:
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);

  • 当图像为多通道图像时,OpenCV 的 Mat 图像内存仍然是连续的,HImage 是多个单通道图像的组合,因此内存组织上有些区别,需要逐个像素整理
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];
	}
}

示例代码
#include<stdio.h>
#include<opencv2/opencv.hpp>
#include"HalconCpp.h"
#include<string>
usingnamespace std;
usingnamespace cv;
usingnamespace 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);
		cout << "Gray" << endl;
	}
elseif (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];
			}
		}
		cout << "RGB" << endl;
	}
return cv_img;
}
intmain()
{
	string data_path = "1.jpg";
HalconCpp::HImage Image(data_path.c_str()), ImageGray;
Rgb1ToGray(Image, &ImageGray);
	Mat cv_img_gray = HImageToMat(ImageGray);
	Mat cv_img_rgb = HImageToMat(Image);
return0;
}

其他深度图像

  • 当图像深度不为 8 bits 时,Mat 图像为连续的内存,HImage 图像仍为多个通道单独处理内存的情况,内存拷贝时需要注意转换前后的图像的位深度一致
示例代码
#include<stdio.h>
#include<opencv2/opencv.hpp>
#include"HalconCpp.h"
#include<string>
usingnamespace std;
usingnamespace cv;
usingnamespace HalconCpp;
intmain()
{
	string data_path = "1.jpg";
HalconCpp::HImage Image(data_path.c_str()), ImageGray;
Rgb1ToGray(Image, &ImageGray);
ConvertImageType(ImageGray, &ImageGray, "int4");
	HTuple channels, w, h;
	HTuple pointer;
CountChannels(ImageGray, &channels);
GetImagePointer1(ImageGray, &pointer, nullptr, &w, &h);
int width = w.I(), height = h.I();
int size = width * height;
	Mat cv_img, cv_res;
	cv_img = cv::Mat::zeros(height, width, CV_32S);
memcpy(cv_img.data, (void*)(pointer.L()), size * 4);
	cv_img.convertTo(cv_res, CV_8UC1);
return0;
}

Mat to HImage

  • 图像转换逻辑和 HImage 转 Mat 是一致的,直接上示例代码
示例代码
#include<stdio.h>
#include<opencv2/opencv.hpp>
#include"HalconCpp.h"
#include<string>
usingnamespace std;
usingnamespace cv;
usingnamespace HalconCpp;
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;
	}
elseif (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;
}
intmain()
{
	string data_path = "1.jpg";
	cv::Mat cv_img = cv::imread(data_path);
	HImage H_img_new = MatToHImage(cv_img);
	Mat cv_img_gray;
cvtColor(cv_img, cv_img_gray, COLOR_RGB2GRAY);
	HImage H_img_gray = MatToHImage(cv_img_gray);
return0;
}

参考资料