halcon+csharp多图像拼接实现
简单的来说,就是将
一类的图片最后拼接成为这样的结果
这个图片有点大呀。
基本步骤:
1、halcon进行仿射变化进行镜头畸变。这个可以参考halcon中一个二维码畸变的例子;
2、基于模版匹配找出偏移值,然后进行拼接。这个可以参考halcon中一个拼接的例子;
3、对交接处进行融合,这个是本文的关键。
首先,这个融合halcon中是没有方法的,所以要自己实现。首先要看论文《基于Halcon的图像拼接算法研究_谭杰》。然后文中有两种方法,因为本例没有产生旋转,所以采用第一种就可以。融合部分代码如下
for i:=RowStart to RowEnd by 1
for j:=450 to 1560 by 1
get_grayval(Imageresult1, i,100, Grayval1)
get_grayval(Imageresult2, i, 100, Grayval2)
grayval0 := (Grayval1 * yinzhi + Grayval2 * (100-yinzhi))/100
set_grayval(Imageresult0, i, j, grayval0)
endfor
yinzhi := yinzhi -1
endfor
接下来就是效率问题,由于halcon是高级语言,为了提高效率,需要在csharp中直接操作内存,进行类似的操作。所以需要将这段代码改写成为csharp的形式。代码如下
using System;
using System.Collections.Generic;
using System.Text;
//新添加
using HalconDotNet;
//2013年10月24日14:54:09 所有图片融和的重构
namespace Halcon10test
{
public class HalconHepler
{
#region 停止HDevelopStop
public void HDevelopStop()
{
}
#endregion
#region 显示继续信息 disp_continue_message
public void disp_continue_message(HTuple hv_WindowHandle, HTuple hv_Color, HTuple hv_Box)
{
HTuple hv_ContinueMessage, hv_Row, hv_Column;
HTuple hv_Width, hv_Height, hv_Ascent, hv_Descent, hv_TextWidth;
HTuple hv_TextHeight;
hv_ContinueMessage = "按下(F5)程序将继续";
HOperatorSet.GetWindowExtents(hv_WindowHandle, out hv_Row, out hv_Column, out hv_Width,
out hv_Height);
HOperatorSet.GetStringExtents(hv_WindowHandle, (" " + hv_ContinueMessage) + " ",
out hv_Ascent, out hv_Descent, out hv_TextWidth, out hv_TextHeight);
disp_message(hv_WindowHandle, hv_ContinueMessage, "window", (hv_Height - hv_TextHeight) - 12,
(hv_Width - hv_TextWidth) - 12, hv_Color, hv_Box);
return;
}
#endregion
#region 显示信息
public void disp_message(HTuple hv_WindowHandle, HTuple hv_String, HTuple hv_CoordSystem,
HTuple hv_Row, HTuple hv_Column, HTuple hv_Color, HTuple hv_Box)
{
HTuple hv_Red, hv_Green, hv_Blue, hv_Row1Part;
HTuple hv_Column1Part, hv_Row2Part, hv_Column2Part, hv_RowWin;
HTuple hv_ColumnWin, hv_WidthWin, hv_HeightWin, hv_MaxAscent;
HTuple hv_MaxDescent, hv_MaxWidth, hv_MaxHeight, hv_R1 = new HTuple();
HTuple hv_C1 = new HTuple(), hv_FactorRow = new HTuple(), hv_FactorColumn = new HTuple();
HTuple hv_Width = new HTuple(), hv_Index = new HTuple(), hv_Ascent = new HTuple();
HTuple hv_Descent = new HTuple(), hv_W = new HTuple(), hv_H = new HTuple();
HTuple hv_FrameHeight = new HTuple(), hv_FrameWidth = new HTuple();
HTuple hv_R2 = new HTuple(), hv_C2 = new HTuple(), hv_DrawMode = new HTuple();
HTuple hv_Exception = new HTuple(), hv_CurrentColor = new HTuple();
HTuple hv_Color_COPY_INP_TMP = hv_Color.Clone();
HTuple hv_Column_COPY_INP_TMP = hv_Column.Clone();
HTuple hv_Row_COPY_INP_TMP = hv_Row.Clone();
HTuple hv_String_COPY_INP_TMP = hv_String.Clone();
HOperatorSet.GetRgb(hv_WindowHandle, out hv_Red, out hv_Green, out hv_Blue);
HOperatorSet.GetPart(hv_WindowHandle, out hv_Row1Part, out hv_Column1Part, out hv_Row2Part,
out hv_Column2Part);
HOperatorSet.GetWindowExtents(hv_WindowHandle, out hv_RowWin, out hv_ColumnWin,
out hv_WidthWin, out hv_HeightWin);
HOperatorSet.SetPart(hv_WindowHandle, 0, 0, hv_HeightWin - 1, hv_WidthWin - 1);
//
//default settings
if ((int)(new HTuple(hv_Row_COPY_INP_TMP.TupleEqual(-1))) != 0)
{
hv_Row_COPY_INP_TMP = 12;
}
if ((int)(new HTuple(hv_Column_COPY_INP_TMP.TupleEqual(-1))) != 0)
{
hv_Column_COPY_INP_TMP = 12;
}
if ((int)(new HTuple(hv_Color_COPY_INP_TMP.TupleEqual(new HTuple()))) != 0)
{
hv_Color_COPY_INP_TMP = "";
}
//
hv_String_COPY_INP_TMP = ((("" + hv_String_COPY_INP_TMP) + "")).TupleSplit("\n");
//
//Estimate extentions of text depending on font size.
HOperatorSet.GetFontExtents(hv_WindowHandle, out hv_MaxAscent, out hv_MaxDescent,
out hv_MaxWidth, out hv_MaxHeight);
if ((int)(new HTuple(hv_CoordSystem.TupleEqual("window"))) != 0)
{
hv_R1 = hv_Row_COPY_INP_TMP.Clone();
hv_C1 = hv_Column_COPY_INP_TMP.Clone();
}
else
{
//transform image to window coordinates
hv_FactorRow = (1.0 * hv_HeightWin) / ((hv_Row2Part - hv_Row1Part) + 1);
hv_FactorColumn = (1.0 * hv_WidthWin) / ((hv_Column2Part - hv_Column1Part) + 1);
hv_R1 = ((hv_Row_COPY_INP_TMP - hv_Row1Part) + 0.5) * hv_FactorRow;
hv_C1 = ((hv_Column_COPY_INP_TMP - hv_Column1Part) + 0.5) * hv_FactorColumn;
}
//
//display text box depending on text size
if ((int)(new HTuple(hv_Box.TupleEqual("true"))) != 0)
{
//calculate box extents
hv_String_COPY_INP_TMP = (" " + hv_String_COPY_INP_TMP) + " ";
hv_Width = new HTuple();
for (hv_Index = 0; (int)hv_Index <= (int)((new HTuple(hv_String_COPY_INP_TMP.TupleLength()
)) - 1); hv_Index = (int)hv_Index + 1)
{
HOperatorSet.GetStringExtents(hv_WindowHandle, hv_String_COPY_INP_TMP.TupleSelect(
hv_Index), out hv_Ascent, out hv_Descent, out hv_W, out hv_H);
hv_Width = hv_Width.TupleConcat(hv_W);
}
hv_FrameHeight = hv_MaxHeight * (new HTuple(hv_String_COPY_INP_TMP.TupleLength()
));
hv_FrameWidth = (((new HTuple(0)).TupleConcat(hv_Width))).TupleMax();
hv_R2 = hv_R1 + hv_FrameHeight;
hv_C2 = hv_C1 + hv_FrameWidth;
//display rectangles
HOperatorSet.GetDraw(hv_WindowHandle, out hv_DrawMode);
HOperatorSet.SetDraw(hv_WindowHandle, "fill");
HOperatorSet.SetColor(hv_WindowHandle, "light gray");
HOperatorSet.DispRectangle1(hv_WindowHandle, hv_R1 + 3, hv_C1 + 3, hv_R2 + 3, hv_C2 + 3);
HOperatorSet.SetColor(hv_WindowHandle, "white");
HOperatorSet.DispRectangle1(hv_WindowHandle, hv_R1, hv_C1, hv_R2, hv_C2);
HOperatorSet.SetDraw(hv_WindowHandle, hv_DrawMode);
}
else if ((int)(new HTuple(hv_Box.TupleNotEqual("false"))) != 0)
{
hv_Exception = "Wrong value of control parameter Box";
throw new HalconException(hv_Exception);
}
//Write text.
for (hv_Index = 0; (int)hv_Index <= (int)((new HTuple(hv_String_COPY_INP_TMP.TupleLength()
)) - 1); hv_Index = (int)hv_Index + 1)
{
hv_CurrentColor = hv_Color_COPY_INP_TMP.TupleSelect(hv_Index % (new HTuple(hv_Color_COPY_INP_TMP.TupleLength()
)));
if ((int)((new HTuple(hv_CurrentColor.TupleNotEqual(""))).TupleAnd(new HTuple(hv_CurrentColor.TupleNotEqual(
"auto")))) != 0)
{
HOperatorSet.SetColor(hv_WindowHandle, hv_CurrentColor);
}
else
{
HOperatorSet.SetRgb(hv_WindowHandle, hv_Red, hv_Green, hv_Blue);
}
hv_Row_COPY_INP_TMP = hv_R1 + (hv_MaxHeight * hv_Index);
HOperatorSet.SetTposition(hv_WindowHandle, hv_Row_COPY_INP_TMP, hv_C1);
HOperatorSet.WriteString(hv_WindowHandle, hv_String_COPY_INP_TMP.TupleSelect(
hv_Index));
}
//reset changed window settings
HOperatorSet.SetRgb(hv_WindowHandle, hv_Red, hv_Green, hv_Blue);
HOperatorSet.SetPart(hv_WindowHandle, hv_Row1Part, hv_Column1Part, hv_Row2Part,
hv_Column2Part);
return;
}
#endregion
#region 设置字体
public void set_display_font(HTuple hv_WindowHandle, HTuple hv_Size, HTuple hv_Font,
HTuple hv_Bold, HTuple hv_Slant)
{
HTuple hv_OS, hv_Exception = new HTuple();
HTuple hv_AllowedFontSizes = new HTuple(), hv_Distances = new HTuple();
HTuple hv_Indices = new HTuple();
HTuple hv_Bold_COPY_INP_TMP = hv_Bold.Clone();
HTuple hv_Font_COPY_INP_TMP = hv_Font.Clone();
HTuple hv_Size_COPY_INP_TMP = hv_Size.Clone();
HTuple hv_Slant_COPY_INP_TMP = hv_Slant.Clone();
HOperatorSet.GetSystem("operating_system", out hv_OS);
if ((int)((new HTuple(hv_Size_COPY_INP_TMP.TupleEqual(new HTuple()))).TupleOr(
new HTuple(hv_Size_COPY_INP_TMP.TupleEqual(-1)))) != 0)
{
hv_Size_COPY_INP_TMP = 16;
}
if ((int)(new HTuple((((hv_OS.TupleStrFirstN(2)).TupleStrLastN(0))).TupleEqual(
"Win"))) != 0)
{
//set font on Windows systems
if ((int)((new HTuple((new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("mono"))).TupleOr(
new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("Courier"))))).TupleOr(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual(
"courier")))) != 0)
{
hv_Font_COPY_INP_TMP = "Courier New";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("sans"))) != 0)
{
hv_Font_COPY_INP_TMP = "Arial";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("serif"))) != 0)
{
hv_Font_COPY_INP_TMP = "Times New Roman";
}
if ((int)(new HTuple(hv_Bold_COPY_INP_TMP.TupleEqual("true"))) != 0)
{
hv_Bold_COPY_INP_TMP = 1;
}
else if ((int)(new HTuple(hv_Bold_COPY_INP_TMP.TupleEqual("false"))) != 0)
{
hv_Bold_COPY_INP_TMP = 0;
}
else
{
hv_Exception = "Wrong value of control parameter Bold";
throw new HalconException(hv_Exception);
}
if ((int)(new HTuple(hv_Slant_COPY_INP_TMP.TupleEqual("true"))) != 0)
{
hv_Slant_COPY_INP_TMP = 1;
}
else if ((int)(new HTuple(hv_Slant_COPY_INP_TMP.TupleEqual("false"))) != 0)
{
hv_Slant_COPY_INP_TMP = 0;
}
else
{
hv_Exception = "Wrong value of control parameter Slant";
throw new HalconException(hv_Exception);
}
try
{
HOperatorSet.SetFont(hv_WindowHandle, ((((((("-" + hv_Font_COPY_INP_TMP) + "-") + hv_Size_COPY_INP_TMP) + "-*-") + hv_Slant_COPY_INP_TMP) + "-*-*-") + hv_Bold_COPY_INP_TMP) + "-");
}
// catch (Exception)
catch (HalconException HDevExpDefaultException1)
{
HDevExpDefaultException1.ToHTuple(out hv_Exception);
throw new HalconException(hv_Exception);
}
}
else
{
//set font for UNIX systems
hv_Size_COPY_INP_TMP = hv_Size_COPY_INP_TMP * 1.25;
hv_AllowedFontSizes = new HTuple();
hv_AllowedFontSizes[0] = 11;
hv_AllowedFontSizes[1] = 14;
hv_AllowedFontSizes[2] = 17;
hv_AllowedFontSizes[3] = 20;
hv_AllowedFontSizes[4] = 25;
hv_AllowedFontSizes[5] = 34;
if ((int)(new HTuple(((hv_AllowedFontSizes.TupleFind(hv_Size_COPY_INP_TMP))).TupleEqual(
-1))) != 0)
{
hv_Distances = ((hv_AllowedFontSizes - hv_Size_COPY_INP_TMP)).TupleAbs();
HOperatorSet.TupleSortIndex(hv_Distances, out hv_Indices);
hv_Size_COPY_INP_TMP = hv_AllowedFontSizes.TupleSelect(hv_Indices.TupleSelect(
0));
}
if ((int)((new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("mono"))).TupleOr(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual(
"Courier")))) != 0)
{
hv_Font_COPY_INP_TMP = "courier";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("sans"))) != 0)
{
hv_Font_COPY_INP_TMP = "helvetica";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("serif"))) != 0)
{
hv_Font_COPY_INP_TMP = "times";
}
if ((int)(new HTuple(hv_Bold_COPY_INP_TMP.TupleEqual("true"))) != 0)
{
hv_Bold_COPY_INP_TMP = "bold";
}
else if ((int)(new HTuple(hv_Bold_COPY_INP_TMP.TupleEqual("false"))) != 0)
{
hv_Bold_COPY_INP_TMP = "medium";
}
else
{
hv_Exception = "Wrong value of control parameter Bold";
throw new HalconException(hv_Exception);
}
if ((int)(new HTuple(hv_Slant_COPY_INP_TMP.TupleEqual("true"))) != 0)
{
if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("times"))) != 0)
{
hv_Slant_COPY_INP_TMP = "i";
}
else
{
hv_Slant_COPY_INP_TMP = "o";
}
}
else if ((int)(new HTuple(hv_Slant_COPY_INP_TMP.TupleEqual("false"))) != 0)
{
hv_Slant_COPY_INP_TMP = "r";
}
else
{
hv_Exception = "Wrong value of control parameter Slant";
throw new HalconException(hv_Exception);
}
try
{
HOperatorSet.SetFont(hv_WindowHandle, ((((((("-adobe-" + hv_Font_COPY_INP_TMP) + "-") + hv_Bold_COPY_INP_TMP) + "-") + hv_Slant_COPY_INP_TMP) + "-normal-*-") + hv_Size_COPY_INP_TMP) + "-*-*-*-*-*-*-*");
}
// catch (Exception)
catch (HalconException HDevExpDefaultException1)
{
HDevExpDefaultException1.ToHTuple(out hv_Exception);
throw new HalconException(hv_Exception);
}
}
return;
}
#endregion
#region 核心函数
//核心过程
public unsafe void action(object objectname)
{
//参数处理
string filename = (string)objectname;
string[] str = filename.Split(',');
string inputname = str[0];
string outputname = str[1];
if (string.Empty == inputname)
{
return;
}
if (string.Empty == outputname)
{
return;
}
//变量定义和初始化
HObject[] OTemp = new HObject[20];
long SP_O = 0;
HObject ho_ImageTemplete, ho_Image1, ho_Image2, ho_ImageTmp;
HObject ho_Image11, ho_Image22, ho_ModelRegion, ho__TmpRegion;
HObject ho_TemplateImage, ho_ModelContours, ho_Images1;
HObject ho_Images2, ho_Black, ho_Imageresult0, ho_Imageresult2;
HObject ho_Imageresult1;
HTuple hv_Pointer_tmp0, hv_Type_tmp0, hv_Width_tmp0, hv_Height_tmp0;
HTuple hv_Pointer_tmp1, hv_Type_tmp1, hv_Width_tmp1, hv_Height_tmp1;
HTuple hv_Pointer_tmp2, hv_Type_tmp2, hv_Width_tmp2, hv_Height_tmp2;
HTuple hv_HomMat2D, hv_Pointer, hv_Type, hv_Width;
HTuple hv_Height, hv_ImageFiles, hv_Index, hv_ModelId;
HTuple hv_Row1, hv_Col1, hv_Angle1, hv_Score1, hv_Row2;
HTuple hv_Col2, hv_Angle2, hv_Score2, hv_i, hv_H = new HTuple();
HTuple hv_j = new HTuple(), hv_a = new HTuple(), hv_b = new HTuple();
HTuple hv_Grayval1 = new HTuple(), hv_Grayval2 = new HTuple();
HTuple hv_grayval = new HTuple();
HOperatorSet.GenEmptyObj(out ho_ImageTemplete);
HOperatorSet.GenEmptyObj(out ho_Image1);
HOperatorSet.GenEmptyObj(out ho_Image2);
HOperatorSet.GenEmptyObj(out ho_Image11);
HOperatorSet.GenEmptyObj(out ho_Image22);
HOperatorSet.GenEmptyObj(out ho_ImageTmp);
HOperatorSet.GenEmptyObj(out ho_ModelRegion);
HOperatorSet.GenEmptyObj(out ho__TmpRegion);
HOperatorSet.GenEmptyObj(out ho_TemplateImage);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_Images1);
HOperatorSet.GenEmptyObj(out ho_Images2);
HOperatorSet.GenEmptyObj(out ho_Black);
HOperatorSet.GenEmptyObj(out ho_Imageresult0);
HOperatorSet.GenEmptyObj(out ho_Imageresult2);
HOperatorSet.GenEmptyObj(out ho_Imageresult1);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
}
//图片序列读取
HOperatorSet.ListFiles(inputname, ((new HTuple("files")).TupleConcat(
"follow_links")).TupleConcat("recursive"), out hv_ImageFiles);
HOperatorSet.TupleRegexpSelect(hv_ImageFiles, (new HTuple("\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima)$")).TupleConcat(
"ignore_case"), out hv_ImageFiles);
//if hv_imageFiles.length!=15 这个问题可以下一步考虑
//校正矩阵计算(参数人工设定,也可以机器标定)
ho_ImageTemplete.Dispose();
HOperatorSet.ReadImage(out ho_ImageTemplete, hv_ImageFiles.TupleSelect(0));
HOperatorSet.HomVectorToProjHomMat2d((((new HTuple(0)).TupleConcat(1080)).TupleConcat(
1080)).TupleConcat(0), (((new HTuple(472)).TupleConcat(327)).TupleConcat(
1705)).TupleConcat(1543), (((new HTuple(1)).TupleConcat(1)).TupleConcat(1)).TupleConcat(
1), (((new HTuple(0)).TupleConcat(1080)).TupleConcat(1080)).TupleConcat(0),
(((new HTuple(472)).TupleConcat(472)).TupleConcat(1546)).TupleConcat(1546),
(((new HTuple(1)).TupleConcat(1)).TupleConcat(1)).TupleConcat(1), "normalized_dlt",
out hv_HomMat2D);
HOperatorSet.GetImagePointer1(ho_ImageTemplete, out hv_Pointer, out hv_Type,
out hv_Width, out hv_Height);
HOperatorSet.ReadImage(out ho_Image1, hv_ImageFiles.TupleSelect(1));
ho_Image2.Dispose();
HOperatorSet.ReadImage(out ho_Image2, hv_ImageFiles.TupleSelect(2));
ho_Image11.Dispose();
HOperatorSet.ProjectiveTransImage(ho_Image1, out ho_Image11, hv_HomMat2D, "bilinear",
"false", "false");
ho_Image22.Dispose();
HOperatorSet.ProjectiveTransImage(ho_Image2, out ho_Image22, hv_HomMat2D, "bilinear",
"false", "false");
OTemp[SP_O] = ho_Image22.CopyObj(1, -1);
SP_O++;
ho_Image22.Dispose();
HOperatorSet.CropPart(OTemp[SP_O - 1], out ho_Image22, 100, 0, hv_Width, hv_Height);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
OTemp[SP_O] = ho_Image11.CopyObj(1, -1);
SP_O++;
ho_Image11.Dispose();
HOperatorSet.CropPart(OTemp[SP_O - 1], out ho_Image11, 100, 0, hv_Width, hv_Height);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
//通过模板匹配计算得到偏移值
HOperatorSet.SetSystem("border_shape_models", "false");
ho_ModelRegion.Dispose();
HOperatorSet.GenRectangle1(out ho_ModelRegion, 421.374, 1309.12, 521.374, 1415.2);
ho__TmpRegion.Dispose();
HOperatorSet.GenRectangle1(out ho__TmpRegion, 902.23, 1041.53, 977.66, 1333.17);
OTemp[SP_O] = ho_ModelRegion.CopyObj(1, -1);
SP_O++;
ho_ModelRegion.Dispose();
HOperatorSet.Union2(OTemp[SP_O - 1], ho__TmpRegion, out ho_ModelRegion);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(ho_Image11, ho__TmpRegion, out ho_TemplateImage);
HOperatorSet.CreateShapeModel(ho_TemplateImage, 4, (new HTuple(0)).TupleRad()
, (new HTuple(360)).TupleRad(), (new HTuple(0.7706)).TupleRad(), (new HTuple("point_reduction_high")).TupleConcat(
"no_pregeneration"), "use_polarity", ((new HTuple(21)).TupleConcat(33)).TupleConcat(
5), 16, out hv_ModelId);
ho_ModelContours.Dispose();
HOperatorSet.GetShapeModelContours(out ho_ModelContours, hv_ModelId, 1);
HOperatorSet.FindShapeModel(ho_Image11, hv_ModelId, (new HTuple(0)).TupleRad()
, (new HTuple(0)).TupleRad(), 0.5, 1, 0.5, "least_squares", 4, 0.75, out hv_Row1,
out hv_Col1, out hv_Angle1, out hv_Score1);
HOperatorSet.FindShapeModel(ho_Image22, hv_ModelId, (new HTuple(0)).TupleRad()
, (new HTuple(0)).TupleRad(), 0.1, 1, 0.5, "least_squares", 4, 0.75, out hv_Row2,
out hv_Col2, out hv_Angle2, out hv_Score2);
HOperatorSet.ClearShapeModel(hv_ModelId);
//拼接(注意这里序号为0的图片没有参与拼接),这里假定所有图片的相对偏移是一致的,这在流水线上非常常见。
for (hv_Index = 1; hv_Index <14; hv_Index ++) //14
{
#region hv_Index = 1
if (hv_Index == 1) //第一幅图的情况
{
ho_Image1.Dispose();
HOperatorSet.ReadImage(out ho_Image1, hv_ImageFiles.TupleSelect(hv_Index));
ho_Image2.Dispose();
HOperatorSet.ReadImage(out ho_Image2, hv_ImageFiles.TupleSelect(hv_Index + 1));
ho_Image11.Dispose();
HOperatorSet.ProjectiveTransImage(ho_Image1, out ho_Image11, hv_HomMat2D, "bilinear",
"false", "false");
ho_Image22.Dispose();
HOperatorSet.ProjectiveTransImage(ho_Image2, out ho_Image22, hv_HomMat2D, "bilinear",
"false", "false");
ho_Images1.Dispose();
HOperatorSet.GenEmptyObj(out ho_Images1);
ho_Images2.Dispose();
HOperatorSet.GenEmptyObj(out ho_Images2);
ho_Black.Dispose();
HOperatorSet.GenImageConst(out ho_Black, "byte", hv_Width, hv_Height);
OTemp[SP_O] = ho_Images1.CopyObj(1, -1);
SP_O++;
ho_Images1.Dispose();
HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Image11, out ho_Images1);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
OTemp[SP_O] = ho_Images1.CopyObj(1, -1);
SP_O++;
ho_Images1.Dispose();
HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Image22, out ho_Images1);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
ho_Imageresult0.Dispose();
//hv_Height+hv_Row1-hv_Row2为拼接后图片的长度
HOperatorSet.TileImagesOffset(ho_Images1, out ho_Imageresult0, (new HTuple(0)).TupleConcat(
hv_Row1 - hv_Row2), (new HTuple(0)).TupleConcat(0), (new HTuple(-1)).TupleConcat(
-1), (new HTuple(-1)).TupleConcat(-1), (new HTuple(-1)).TupleConcat(-1),
(new HTuple(-1)).TupleConcat(-1), hv_Width, hv_Height+hv_Row1-hv_Row2);
ho_Imageresult1.Dispose();
HOperatorSet.TileImagesOffset(ho_Image11, out ho_Imageresult1, 0, 0, -1, -1,
-1, -1, hv_Width, hv_Height + hv_Row1 - hv_Row2);
ho_Imageresult2.Dispose();
HOperatorSet.TileImagesOffset(ho_Image22, out ho_Imageresult2, hv_Row1 - hv_Row2,
0, -1, -1, -1, -1, hv_Width, hv_Height + hv_Row1 - hv_Row2);
//交界处融和,关键代码
HOperatorSet.GetImagePointer1(ho_Imageresult0, out hv_Pointer_tmp0, out hv_Type_tmp0, out hv_Width_tmp0, out hv_Height_tmp0);
HOperatorSet.GetImagePointer1(ho_Imageresult1, out hv_Pointer_tmp1, out hv_Type_tmp1, out hv_Width_tmp1, out hv_Height_tmp1);
HOperatorSet.GetImagePointer1(ho_Imageresult2, out hv_Pointer_tmp2, out hv_Type_tmp2, out hv_Width_tmp2, out hv_Height_tmp2);
long lWidth0 = (long)hv_Width_tmp0; //现图
long lHeight0 = (long)hv_Height_tmp0;
long lWidth1 = (long)hv_Width_tmp1; //原图
long lHeight1 = (long)hv_Height_tmp1;
// string sType = hv_Type_tmp.ToString();
Byte* IPByte0 = (Byte*)hv_Pointer_tmp0.I;
Byte* IPByte1 = (Byte*)hv_Pointer_tmp1.I;
Byte* IPByte2 = (Byte*)hv_Pointer_tmp2.I;
/* long lrow = 0; long lcol = 0;*/
int irow1 = (int)hv_Row1.D; //row1
int irow2 = (int)hv_Row2.D;
int irow12 = Math.Abs(irow1 - irow2);
//读取到内存中
Byte[] G1 = new Byte[hv_Height_tmp1 * hv_Width_tmp1];
Byte[] G2 = new Byte[hv_Height_tmp1 * hv_Width_tmp1];
double a = 0; double b = 0;
for (int i = 0; i < lHeight1; i++)
{
for (int j = 0; j < lWidth1; j++)
{
G1[i * lWidth1 + j] = *IPByte1;
G2[i * lWidth1 + j] = *IPByte2;
IPByte1++;
IPByte2++;
}
}
//像素融和循环
for (int lcol = 0; lcol < lWidth0; lcol++)
{
for (int lrow = irow12; lrow < irow1; lrow++)
{
a = 1.0 * (irow1 - lrow) / irow2;
b = 1.0 * (lrow - irow12) / irow2;
IPByte0[lrow * lWidth0 + lcol] = (Byte)(G1[lrow * lWidth0 + lcol] * a + G2[lrow * lWidth0 + lcol] * b);
}
}
//把结果保存下来
HOperatorSet.CopyImage(ho_Imageresult0, out ho_ImageTmp);
#endregion
}
else //不是第一幅图的情况
{
ho_Image1.Dispose();
ho_Image11.Dispose();
HOperatorSet.CopyImage(ho_ImageTmp, out ho_Image1);
HOperatorSet.CopyImage(ho_ImageTmp, out ho_Image11);
ho_Image2.Dispose();
HOperatorSet.ReadImage(out ho_Image2, hv_ImageFiles.TupleSelect(hv_Index + 1));
//第二副图片需要镜头畸变
ho_Image22.Dispose();
HOperatorSet.ProjectiveTransImage(ho_Image2, out ho_Image22, hv_HomMat2D, "bilinear",
"false", "false");
//注意,这里ho_Images1变成图片组了,这个代码风格有问题
ho_Images1.Dispose();
HOperatorSet.GenEmptyObj(out ho_Images1);
ho_Images2.Dispose();
HOperatorSet.GenEmptyObj(out ho_Images2);
OTemp[SP_O] = ho_Images1.CopyObj(1, -1);
SP_O++;
ho_Images1.Dispose();
HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Image11, out ho_Images1);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
OTemp[SP_O] = ho_Images1.CopyObj(1, -1);
SP_O++;
ho_Images1.Dispose();
HOperatorSet.ConcatObj(OTemp[SP_O - 1], ho_Image22, out ho_Images1);
OTemp[SP_O - 1].Dispose();
SP_O = 0;
ho_Imageresult0.Dispose();
//hv_Height +(hv_Row1-hv_Row2)*hv_Index 是拼接后图片的长度
//(hv_Row1-hv_Row2)*hv_Index 是偏移长度
HOperatorSet.TileImagesOffset(ho_Images1, out ho_Imageresult0, (new HTuple(0)).TupleConcat(
(hv_Row1 - hv_Row2) * hv_Index), (new HTuple(0)).TupleConcat(0), (new HTuple(-1)).TupleConcat(
-1), (new HTuple(-1)).TupleConcat(-1), (new HTuple(-1)).TupleConcat(-1),
(new HTuple(-1)).TupleConcat(-1), hv_Width, hv_Height +(hv_Row1-hv_Row2)*hv_Index);
ho_Imageresult1.Dispose();
HOperatorSet.TileImagesOffset(ho_Image11, out ho_Imageresult1, 0, 0, -1, -1,
-1, -1, hv_Width, hv_Height + (hv_Row1 - hv_Row2) * hv_Index);
ho_Imageresult2.Dispose();
HOperatorSet.TileImagesOffset(ho_Image22, out ho_Imageresult2, (hv_Row1 - hv_Row2) * hv_Index,
0, -1, -1, -1, -1, hv_Width, hv_Height + (hv_Row1 - hv_Row2) * hv_Index);
//交界处融和,关键代码
HOperatorSet.GetImagePointer1(ho_Imageresult0, out hv_Pointer_tmp0, out hv_Type_tmp0, out hv_Width_tmp0, out hv_Height_tmp0);
HOperatorSet.GetImagePointer1(ho_Imageresult1, out hv_Pointer_tmp1, out hv_Type_tmp1, out hv_Width_tmp1, out hv_Height_tmp1);
HOperatorSet.GetImagePointer1(ho_Imageresult2, out hv_Pointer_tmp2, out hv_Type_tmp2, out hv_Width_tmp2, out hv_Height_tmp2);
long lWidth0 = (long)hv_Width_tmp0; //现图
long lHeight0 = (long)hv_Height_tmp0;
long lWidth1 = (long)hv_Width_tmp1; //原图
long lHeight1 = (long)hv_Height_tmp1;
long lWidth2 = (long)hv_Width_tmp2; //原图
long lHeight2 = (long)hv_Height_tmp2;
// string sType = hv_Type_tmp.ToString();
Byte* IPByte0 = (Byte*)hv_Pointer_tmp0.I;
Byte* IPByte1 = (Byte*)hv_Pointer_tmp1.I;
Byte* IPByte2 = (Byte*)hv_Pointer_tmp2.I;
/* long lrow = 0; long lcol = 0;*/
int irow1 = (int)hv_Row1.D ; //row1
int irow2 = (int)hv_Row2.D ;
int irow12 = Math.Abs(irow1 - irow2);
//读取到内存中
Byte[] G1 = new Byte[hv_Height_tmp1 * hv_Width_tmp1];
Byte[] G2 = new Byte[hv_Height_tmp2 * hv_Width_tmp2];
double a = 0; double b = 0;
for (int i = 0; i < lHeight1; i++)
{
for (int j = 0; j < lWidth1; j++)
{
G1[i * lWidth1 + j] = *IPByte1;
IPByte1++;
}
}
for (int i = 0; i < lHeight2; i++)
{
for (int j = 0; j < lWidth2; j++)
{
G2[i * lWidth2 + j] = *IPByte2;
IPByte2++;
}
}
IPByte1 = (Byte*)hv_Pointer_tmp1.I;
IPByte2 = (Byte*)hv_Pointer_tmp2.I;
int ioffset = irow12 * (hv_Index-1);
//像素融和循环
for (int lcol = 0; lcol < lWidth0; lcol++)
{
for (int lrow = irow12; lrow < irow1; lrow++)
{
a = 1.0 * (irow1 - lrow) / irow2;
b = 1.0 * (lrow - irow12) / irow2;
IPByte0[(lrow + ioffset) * lWidth0 + lcol] = (Byte)(G1[(lrow + ioffset) * lWidth0 + lcol] * a + G2[(lrow + ioffset) * lWidth0 + lcol] * b);
}
}
//把结果保存下来
HOperatorSet.CopyImage(ho_Imageresult0, out ho_ImageTmp);
}
}
//成功输出结果
HOperatorSet.WriteImage(ho_Imageresult0, "bmp", 0, outputname + "/" + "融合结果.bmp");
ho_ImageTemplete.Dispose();
ho_Image1.Dispose();
ho_Image2.Dispose();
ho_Image11.Dispose();
ho_Image22.Dispose();
ho_ModelRegion.Dispose();
ho__TmpRegion.Dispose();
ho_TemplateImage.Dispose();
ho_ModelContours.Dispose();
ho_Images1.Dispose();
ho_Images2.Dispose();
ho_Black.Dispose();
ho_Imageresult0.Dispose();
ho_Imageresult2.Dispose();
ho_Imageresult1.Dispose();
return;
}
#endregion
}
}
结果运行界面
15张8秒。如果还有问题,请联系1755311380(QQ)
halcon+csharp多图像拼接实现的更多相关文章
- Halcon一日一练:图像拼接技术2:步骤与例程
上一篇主要介绍了图像拼接的一些原理和方法,这一篇将主要介绍步骤和例程: 接上一篇: 基于特征的接拼方法,分为四个步骤 1.特征检测:从图像中检测出显著且独特的图像特征,诸如:闭合区域,直线段,边缘,轮 ...
- Halcon一日一练:图像拼接技术
图像拼接技术就是针对同一场景的一系列图片,根据图片的特征,比如位置,重叠部分等,拼接成一张大幅的宽视角的图像. 图像拼接要求拼接后图像最大程度的与原图一致,失真尽可能的小,并且要尽量做到天衣无缝即没有 ...
- zw版·Halcon与delphi(兼谈opencv)
zw版·Halcon与delphi(兼谈opencv) QQ群 247994767(delphi与halcon) <Halcon与delphi>系列,早两年就想写,不过一方面,因为Halc ...
- 《zw版·Halcon-delphi系列原创教程》 zw版-Halcon常用函数Top100中文速查手册
<zw版·Halcon-delphi系列原创教程> zw版-Halcon常用函数Top100中文速查手册 Halcon函数库非常庞大,v11版有1900多个算子(函数). 这个Top版,对 ...
- zw版·全程图解Halcon控件安装(delphi2007版)
zw版·全程图解Halcon控件安装(delphi2007版) delphi+halcon,这个组合,可以说是图像分析的神级配置,无论是开发效率,还是运行实在是太高了,分分钟秒杀c+opencv,py ...
- 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数·简明中文手册 总览
<zw版·Halcon-delphi系列原创教程> Halcon分类函数·简明中文手册 总览 Halcon函数库非常庞大,光HALCONXLib_TLB.pas文件,源码就要7w多行,但核 ...
- halcon,C# 学习
Halcon学习之一:查询图像参数 1.get_grayval ( Image : : Row, Column : Grayval ) 计算Image图像中坐标为(Row,Column)的点的灰度值G ...
- halcon小结
持更 应用范围 (罗列自官方帮助文档,以后有空了按照需求展开叙述) 1. 安全系统 2. 表面检测 3. 定位 4. 二维测量比较 5. 二维码识别 6. 二维位置定位 7. 二维物体识别 8. 光学 ...
- c#操作MangoDB 之MangoDB CSharp Driver驱动详解
序言 MangoDB CSharp Driver是c#操作mongodb的官方驱动. 官方Api文档:http://api.mongodb.org/csharp/2.2/html/R_Project_ ...
随机推荐
- markdown入门杂记
系统环境:win10 软件:sublime Text 3 安装插件: markdown editing.markdownlivepreview 修改prference-markdownliveprev ...
- 加减plugin
plugin插件↓↓ ;(function (underfined) { "use strict" var _global; //插件函数 /* var plugin = { ad ...
- Vue+webpack项目中实现跨域的http请求
目前Vue项目中对json数据的请求一般使用两个插件vue-resource和axios, 但vue-resource已经不再维护, 而axios是官方推荐的且npm下载量已经170多万,github ...
- c#之正则表达式
一,C#正则表达式符号模式 字 符 描 述 \ 转义字符,将一个具有特殊功能的字符转义为一个普通字符,或反过来 ^ 匹配输入字符串的开始位置 $ 匹配输入字符串的结束位置 * 匹配前面的零次或多次的子 ...
- IntelliJ IDEA总是提示Cannot resolve symbol的解决方案
- python3 TypeError: a bytes-like object is required, not 'str'
在学习<Python web开发学习实录>时, 例11-1: # !/usr/bin/env python # coding=utf-8 import socket sock = sock ...
- [17]Windows的启动过程
一.内核的引导 在intel x86系统上,windows操作系统获得控制首先从硬盘的主引导记录(MBR,Master Boot Record)开始,windows setup程序在安装windows ...
- 变量part2
一 变量值具有三个特征: 1. id:变量值的唯一编号,内存地址不同id则不同 2. type:类型 3. value(值) #name='xia' #print(id(name)) #age= ...
- ios 回调函数作用
//应用程序启动后调用的第一个方法 不懂的程序可以做不同的启动 //launchOption参数的作业:应用在特定条件下的不同启动参数 比如:挑战的支付宝支付 - (BOOL)application: ...
- Another Meaning (KMP + DP)
先用KMP重叠匹配求出各个匹配成功的尾串位置.然后利用DP去求,那转移方程应该是等于 上一个状态 (无法匹配新尾巴) 上一个状态 + 以本次匹配起点为结尾的状态(就是说有了新的位置) + 1 (单单一 ...