最近由于项目需求,需要对相机采集的图像进行实时的处理并及时反馈信息,其中第一步就是对采集目标进行校正。由于我们的相机是斜拍,且处理对象在一次检测完之后需要更换(型号、大小、位置等),而我们的拍摄背景又比较杂乱,因此难以对目标进行准确的分割,所以我准备采用一种比较蠢的方法,因为目标是矩形,所以在每次更换对象之后先人为选择四个角点,作为校正的基准点。校正完毕后,再进行后续的处理工作。为了后期方便测试,领导让我学着自己写个小软件,然后过程中就开始遇到问题了。
这个问题就是,我在采集每一帧图像,然后处理后怎么在另一个窗口实时的进行显示。其实很简单呗,就是新开个线程嘛,但是之前没怎么接触过这类问题,网上资料又比较少,因此就自己摸摸索索搞了好几天才出结果。
我们先看一下效果。我要将这张图里的宝可梦手机壳进行校正并实时显示。
下面贴几个实现的方法。
1.校正算法。OutCorrectedImage。halcon中的一个函数就可以解决了,这个问题便不多赘述。
2.在何处进行校正。这里我是在采集视频的回调函数里进行的。当触发了校正按钮之后,直接在此进行处理。
if (m_bCorrect == true)
{
IntPtr pRaw8Buffer = objIBaseData.ConvertToRaw8(GX_VALID_BIT_LIST.GX_BIT_0_7);
int width = (int)(objIBaseData.GetWidth());
int height = (int)(objIBaseData.GetHeight());
HOperatorSet.GenImage1(out ho_image, "byte", width, height, pRaw8Buffer);
//根据控件大小计算真实的坐标
HTuple hv_zoomPRow = hv_PRow * (height / PictureBoxHeight);
HTuple hv_zoomPCol = hv_PCol * (width / PictureBoxWidth);
ho_TransImage = m_mathImage.OutCorrectedImage(ho_image, hv_zoomPRow, hv_zoomPCol);
}
3.如何新开一个线程在窗口中显示校正后的视频。这里是直接给picturebox.Image赋值(bmp)来达到显示的目的,我尝试过直接显示HObject的方法,不能成功,图像总是会被缩小显示在控件的左上角,至今不知道是怎么回事。。。
private void m_btnCorrect_Click(object sender, EventArgs e)
{
if (hv_PCol.Length == 4)
{
camera.StartCorrect(hv_PRow, hv_PCol);
}
Thread showimage = new Thread(show);
showimage.Start();
}
//开一个代理
public delegate void ShowImage(HObject ho_image);
public void showImage(HObject ho_image)
{
if (this.InvokeRequired)
{
ShowImage show = new ShowImage(showImage);
this.Invoke(show, ho_image );
}
else
{
Bitmap correct;
HObject2Bpp8(ho_image, out correct);
//显示控件必须要refresh,不然无法显示
this.m_picShowCorrectImage.Refresh();
this.m_picShowCorrectImage.Image = correct;
}
}
private void show()
{
while (camera.ho_TransImage != null)
{
System.Threading.Thread.Sleep(10);
showImage(camera.ho_TransImage);
}
}
//如何将灰度HObject图像转化为bmp
[DllImport("kernel32.dll")]
public static extern void CopyMemory(int Destination, int add, int Length);
private void HObject2Bpp8(HObject image, out Bitmap res)
{
HTuple hpoint, type, width, height;
const int Alpha = 255;
int[] ptr = new int[2];
HOperatorSet.GetImagePointer1(image, out hpoint, out type, out width, out height);
res = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
ColorPalette pal = res.Palette;
for (int i = 0; i <= 255; i++)
{
pal.Entries[i] = Color.FromArgb(Alpha, i, i, i);
}
res.Palette = pal;
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bitmapData = res.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
int PixelSize = Bitmap.GetPixelFormatSize(bitmapData.PixelFormat) / 8;
ptr[0] = bitmapData.Scan0.ToInt32();
ptr[1] = hpoint.I;
if (width % 4 == 0)
CopyMemory(ptr[0], ptr[1], width * height * PixelSize);
else
{
for (int i = 0; i < height - 1; i++)
{
ptr[1] += width;
CopyMemory(ptr[0], ptr[1], width * PixelSize);
ptr[0] += bitmapData.Stride;
}
}
res.UnlockBits(bitmapData);
}
好了,以上就是这段时间遇到问题的解决方法,可能不是很完善,后续进一步改进吧~~
相关源码上传到:https://github.com/zhanzhanmiao/video-real-time-display