2024年2月21日发(作者:)

如何使用VC在Halcon中得到像素的信息

Halcon的强大功能使我们省去很多图像处理(机器视觉)中的很多麻烦而又重复性的工作。但是,面向不同的应用,应该编写自己最核心的算法,从而达到最佳的处理效果;而且Halcon并不可能把各种情况都考虑进去。以下是我初步入门Halcon和VC的一点感触和想法,已经被实验证明了是正确的。

1,在VC中,使用Halcon打开图像文件,这里要注意read_image()和get_image_pointer1()指令被HDevelop翻译过来以后如下:

Hobject Image

HTuple Pointer, Type, Width, Height

get_image_pointer1(Image, &Pointer, &Type, &Width, &Height);

VC中如下声明:

Halcon::Hobject Image

Halcon::HTuple Pointer, Type, Width, Height

VC中也可以如下声明使用:

Hobject Image

Char

lpcsType[MAX_STRING]

Hlong Pointer, Width, Height 或 long Width, Height

(如果定义为 HTuple Pointer ; Hlong Width, Height; 编译会出现错误;

使用Halcon::HTuple Pointer, Type, Width, Height的话,后续中需要

图像的高宽时,强制类型转换不可用;

当然Hlong可以换成long,推荐使用Hlong。)

get_image_pointer1(Image, &Pointer,

lpcsType, &Width, &Height);

这里注意,在VC中如果get_image_pointer1( )中的字节类型使用tuple变量,那么Width和Height也必须使用tuple变量,否则编译时候容易出错误,至于原因是什么,可能halcon编译的时候需要各个参数的类型形式一致。

2,tuple类型的返回指针Pointer指向图像数据区域(如果是彩色则指向色彩的第一通道),图像的RGB色彩存放是同一种色彩信号最放在一起。注意Pointer所指向区域的大小比图像必须的色彩信息要大许多,这里可能是因为必须为tuple变量定义一定的类型限制,从而使用的空间变大了(由于不了解tuple的内部存储格式,所以不敢断定)。请看下面一段例子程序:使用Halcon,把彩色图像转化为灰度图像,然后使用Pointer指针得到灰度图像并显示,包括在VC窗口中进行显示部分。

using namespace Halcon;

char lpcsType[MAX_STRING];

Hlong PointerGray,WidthGray, HeightGray;

rgb1_to_gray(objImage, &objImageGray);

get_image_pointer1(objImage, &PointerGray, lpcsType, &WidthGray, &HeightGray);

BYTE * lpByte;

BYTE * ImageGray;

int bytewidth;

bytewidth = ((long) WidthGray * 3 + 3 ) / 4 * 4 ;

ImageGray = NULL ;

ImageGray = new BYTE[ bytewidth * (long) HeightGray];

lpByte = (BYTE *) PointerGray; //注意结合图像像素存储的类型进行定义

int i,j;

for( j = (long)HeightGray-1; j>=0; j--)

{ //(注意tuple中图像数据的存放和VC中的差别)

for( i = 0; i < (long)WidthGray; i++)

{

* (ImageGray + j * bytewidth + i * 3 + 0 ) = * lpByte ;

* (ImageGray + j * bytewidth + i * 3 + 1 ) = * lpByte ;

* (ImageGray + j * bytewidth + i * 3 + 2 ) = * lpByte ;

lpByte++;

}

}

BITMAPINFO * RotateBmpInfo;

BYTE * bitBuffer;

bitBuffer = NULL;

bitBuffer = new BYTE[sizeof(BITMAPINFO)];

RotateBmpInfo = (BITMAPINFO *)bitBuffer;

RotateBmpInfo-> = sizeof(BITMAPINFOHEADER);

RotateBmpInfo->ht = HeightGray;

RotateBmpInfo->h = WidthGray;

RotateBmpInfo->es = 1;

RotateBmpInfo->ount = 24;

RotateBmpInfo->ression = BI_RGB;

RotateBmpInfo->Image = HeightGray * bytewidth;

RotateBmpInfo->sPerMeter= 0;

RotateBmpInfo->sPerMeter= 0;

RotateBmpInfo->sed = 0;

RotateBmpInfo->mportant = 0;

CWnd * m_pWnd ;

m_pWnd = AfxGetApp()->GetMainWnd();

CDC *ddc = m_pWnd->GetDC();

::StretchDIBits(

ddc->GetSafeHdc(),

WidthGray + 10,

HeightGray + 10,

WidthGray, //显示窗口宽度

HeightGray, //显示窗口高度

0,

0,

WidthGray, //图像宽度

HeightGray, //图像高度

ImageGray,

RotateBmpInfo,

DIB_RGB_COLORS,

SRCCOPY);

m_pWnd->ReleaseDC(ddc) ;

delete []ImageGray ;

delete []bitBuffer ;

后来实验发现,如果按照HDevelop默认翻译过来的规则写C++程序,如下:

Halcon::Hobject Image

Halcon::HTuple Pointer, Type, Width, Height

操作get_image_pointer1(objImage, &Pointer, &Type, &Width, &Height)

执行以后,可以使用Width[0],Height[0]进行数据访问,但是命令:

lpByte = (BYTE *) PointerGray;

不能够执行,作者也在进一步弄清楚如何解决这个问题,请大家给点帮助。

今天在调试程序中发现一个问题,再次让我感受Halcon内存管理的神秘,嘿嘿,说说问题吧

Hlong PointerGray, PointerRed, PointerGreen, PointerBlue;

Hlong WidthGray, HeightGray;

get_image_pointer1(objImageGray, &PointerGray, lpcsType, &WidthGray,

&HeightGray);

编译可以通过,但是

Hlong PointerGray, PointerRed, PointerGreen, PointerBlue;

Hlong WidthGray, HeightGray;

get_image_pointer3(objImage, &PointerRed, &PointerGreen, &PointerBlue,

&lpcsType, &WidthGray, &HeightGray);

编译就通不过,大家可以试一下

如果需要,可以使用 decompose3(objImage, &objImageRed, &objImageGreen,

&objImageGray);

然后使用函数get_image_pointer1()得到指针

我个人认为是Halcon的变量类型讲究统一,如果是Tuple都是Tuple,我个人认为PointerRed,PointerGreen,PointerBlue可能是Tuple变量中的三个量,而HeightGray不是按照Tuple变量进行管理的,纯属个人猜测,大家有想法的给我回,或发邮件*********************或者**************************

1.从Halcon到VC++

read_image(&Image,"文件名");//读入的为灰度图像

//获取图像指针,注意输出变量的类型

char lpcsType[MAX_STRING];

Hlong Pointer,Width, Height;

get_image_pointer1(Image, &Pointer, lpcsType, &Width, &Height);

//Halcon与VC++中的图像之间,存在着上下翻转

BYTE * lpByte;

BYTE * ImageG;

int bytewidth;

bytewidth = ((long) Width * 3 + 3 ) / 4 * 4 ;

ImageG = NULL ;

ImageG = new BYTE[ bytewidth * (long) Height ];

lpByte = (BYTE *) Pointer; //注意结合图像像素存储的类型进行定义

int i,j;

for( j = (long)Height-1; j>=0; j--)

{ //(注意tuple中图像数据的存放和VC中的差别)

for( i = 0; i < (long)WidthGray; i++)

{

* (ImageG + j * bytewidth + i * 3 + 0 ) = * lpByte ;

* (ImageG + j * bytewidth + i * 3 + 1 ) = * lpByte ;

* (ImageG + j * bytewidth + i * 3 + 2 ) = * lpByte ;

lpByte++;

}

}

BITMAPINFO * RotateBmpInfo;

BYTE * bitBuffer;

bitBuffer = NULL;

bitBuffer = new BYTE[sizeof(BITMAPINFO)];

RotateBmpInfo = (BITMAPINFO *)bitBuffer;

RotateBmpInfo-> = sizeof(BITMAPINFOHEADER);

RotateBmpInfo->ht = Height;

RotateBmpInfo->h = Width;

RotateBmpInfo->es = 1;

RotateBmpInfo->ount = 24;

RotateBmpInfo->ression = BI_RGB;

RotateBmpInfo->Image = Height * bytewidth;

RotateBmpInfo->sPerMeter= 0;

RotateBmpInfo->sPerMeter= 0;

RotateBmpInfo->sed = 0;

RotateBmpInfo->mportant = 0;

CWnd * m_pWnd ;

m_pWnd = AfxGetApp()->GetMainWnd();

CDC *pDC = m_pWnd->GetDC();

::StretchDIBits(

pDC->GetSafeHdc(),

Width + 10,

Height + 10,

Width, //显示窗口宽度

Height, //显示窗口高度

0,

0,

Width, //图像宽度

Height, //图像高度

ImageG,

RotateBmpInfo,

DIB_RGB_COLORS,

SRCCOPY);

m_pWnd->ReleaseDC(pDC);

delete [] ImageG ;

delete [] bitBuffer ;

2. 从VC++到Halcon

unsigned char *Pointer;

int width, height;

Pointer = new unsigned char[width * height];

int i, j;

for (i=0; i

{

for (j=0; j

{

Pointer = j % 255;

}

}

Hobject Image;

gen_image1_extern(&Image, "byte", (HTuple)width, (HTuple)height, (long)Pointer,

NULL);

注:

a) gen_image1_extern函数中的变量width,height必须为HTuple类型,Pointer指针为unsigned char类型,输入时转换为long型。

b) width, height必须与Pointer指向的图像数据的长宽一致。

c) Pointer指针在gen_image1_extern函数调用之前分配了内存,之后不要马上释放,否则会出错。应该在确保不再使用Image变量之后再释放。halcon内部会自动释放Image,感觉没有释放Pointer(还需要进一步验证)。

d) 显示图像时,可能存在着图像的上下翻转,可以按照1中的方法,将图像数据翻转后再调用gen_image1_extern,或者使用halcon中的函数mirror_image()进行翻转。

3.在VC界面中建立图像窗口

Hlong lWWindowID;

HTuple WindowHandle;

lWWindowID = (Hlong)m_hWnd; //要显示图片的控件的句柄

set_window_attr("border_width",0); //设置窗口属性

set_window_attr("background_color","light gray"); //设置窗口背景颜色

set_check("~father");

open_window(0,0,m_Width,m_Height,lWWindowID,"visible","",&WindowHandle); //创建窗口

set_check("father");

set_part(WindowHandle,0,0,m_Width-1,m_Height-1); //对窗口上显示图像和区域的一些设置

set_draw(WindowHandle,"margin");

set_colored(WindowHandle,12);

disp_obj(Image,WindowHandle); //显示图像Image(Hobject类型)

4.从HTuple类型读取数据

//HTuple有一个元素

HTuple aa = 120;

double dd = aa[0].D(); // dd=120.000

int ii = aa[0].I(); //ii=120

long ll = aa[0].L(); //ll=120

Hlong hh = aa[0].L();//hh=120

long num = (); //num =1;

aa = "120"; //HTuple为字符串时,如果赋值不是字符串,不能调用S()函数

const char *cc;

cc = aa[0].S(); //cc[0]='1',cc[1]='2',cc[2]='0'

//当aa为多元素的数组时

aa[1] = 230;

num = (); //num =2;

ii = aa[1].I(); //ii=230 //其他获取数据的方法与上面类似