- 本案例分3部分
- 识别效果,分别显示识别前后识别后;
- 代码展示,分别是Halcon源码和Halcon转为C#的代码
- 代码解释(解释在源码中);
- 原图如下
识别后图像:
其中计算回形针与X轴之间的夹角
Halcon代码:
* clip.hdev: Orientation of clips
*识别图像中的回形针,并且计算回形针与X轴之间的夹角
*
*打开一张图像
read_image (Clip, 'clip')
*获取图像大小
get_image_size (Clip, Width, Height)
*关闭已经打开的窗口
dev_close_window ()
*打开新窗口
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowID)
*在新窗口里显示图像
dev_display (Clip)
*设置窗口字体显示,字体大小,字体样式,粗体,斜体
set_display_font (WindowID, 14, 'mono', 'true', 'false')
*在窗口右下方显示"Press Run (F5) to continue"字样
*disp_continue_message (WindowID, 'black', 'true')
*停止程序的执行
*stop ()
*二值化操作
binary_threshold (Clip, Dark, 'max_separability', 'dark', UsedThreshold)
*将区域进行连通处理
connection (Dark, Single)
*过滤出面积大小在【5000, 10000】范围里的区域
select_shape (Single, Selected, 'area', 'and', 5000, 10000)
*设置区域的填充方式
dev_set_draw ('fill')
*设置输出显示对象的颜色数目
dev_set_colored (12)
*在窗口右下方显示"Press Run (F5) to continue"字样
*disp_continue_message (WindowID, 'black', 'true')
*停止程序的执行
*stop ()
*显示图像
dev_display (Clip)
*设置输出对象的颜色为绿色
dev_set_color ('yellow')
*显示过滤后的区域
dev_display (Selected)
*获取过滤后区域的方向
orientation_region (Selected, Phi)
*获取过滤后区域的面积,中心的行坐标,列坐标
area_center (Selected, Area, Row, Column)
*设置输出对象的线宽为3
dev_set_line_width (3)
*设置区域的填充方式
dev_set_draw ('margin')
Length := 80
*设置输出对象的颜色为蓝色
dev_set_color ('orange red')
*在窗口上显示十字
disp_arrow (WindowID, Row, Column, Row - Length * sin(Phi), Column + Length * cos(Phi), 4)
*在窗口上显示回形针的角度 将弧度转为角度deg(Phi)
disp_message (WindowID, deg(Phi)$'3.1f' + ' deg', 'image', Row, Column - 100, 'black', 'false')
C#代码:
#region 识别回形针方向
/// <summary>
/// 识别图像中的回形针,并且计算回形针与X轴之间的夹角
/// </summary>
public void RecognizeClipDirection(HTuple winId, string imagePath)
{
HObject ho_Clip, ho_Dark, ho_Single, ho_Selected;
// Local control variables
HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
HTuple hv_UsedThreshold = new HTuple();
HTuple hv_Phi = new HTuple(), hv_Area = new HTuple(), hv_Row = new HTuple();
HTuple hv_Column = new HTuple(), hv_Length = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Clip);
HOperatorSet.GenEmptyObj(out ho_Dark);
HOperatorSet.GenEmptyObj(out ho_Single);
HOperatorSet.GenEmptyObj(out ho_Selected);
try
{
//clip.hdev: Orientation of clips
//打开一张图像
ho_Clip.Dispose();
HOperatorSet.ReadImage(out ho_Clip, imagePath);
//获取图像大小
//hv_Width.Dispose();
//hv_Height.Dispose();
//HOperatorSet.GetImageSize(ho_Clip, out hv_Width, out hv_Height);
//打开新窗口
//HOperatorSet.SetWindowAttr("background_color", "black");
//HOperatorSet.OpenWindow(0, 0, hv_Width / 2, hv_Height / 2, 0, "visible", "", out winId);
//HDevWindowStack.Push(winId);
//在新窗口里显示图像
HOperatorSet.DispObj(ho_Clip, winId);
//设置窗口字体显示,字体大小,字体样式,粗体,斜体
Set_display_font(winId, 14, "mono", "true", "false");
//二值化操作
ho_Dark.Dispose();
hv_UsedThreshold.Dispose();
HOperatorSet.BinaryThreshold(ho_Clip, out ho_Dark, "max_separability", "dark", out hv_UsedThreshold);
//将区域进行连通处理
ho_Single.Dispose();
HOperatorSet.Connection(ho_Dark, out ho_Single);
//过滤出面积大小在【5000, 10000】范围里的区域
ho_Selected.Dispose();
HOperatorSet.SelectShape(ho_Single, out ho_Selected, "area", "and", 5000, 10000);
//设置区域的填充方式
HOperatorSet.SetDraw(winId, "fill");
//设置输出显示对象的颜色数目
HOperatorSet.SetColored(winId, 12);
//显示图像
HOperatorSet.DispObj(ho_Clip, winId);
//设置输出对象的颜色为绿色
HOperatorSet.SetColor(winId, "yellow");
//显示过滤后的区域
HOperatorSet.DispObj(ho_Selected, winId);
//获取过滤后区域的方向
hv_Phi.Dispose();
HOperatorSet.OrientationRegion(ho_Selected, out hv_Phi);
//获取过滤后区域的面积,中心的行坐标,列坐标
hv_Area.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
HOperatorSet.AreaCenter(ho_Selected, out hv_Area, out hv_Row, out hv_Column);
//设置输出对象的线宽为3
HOperatorSet.SetLineWidth(winId, 3);
//设置区域的填充方式
HOperatorSet.SetDraw(winId, "margin");
hv_Length.Dispose();
hv_Length = 80;
//设置输出对象的颜色为蓝色
HOperatorSet.SetColor(winId, "orange red");
//在窗口上显示十字
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
HOperatorSet.DispArrow(winId, hv_Row, hv_Column, hv_Row - (hv_Length * hv_Phi.TupleSin()), hv_Column + (hv_Length * (hv_Phi.TupleCos())), 4);
}
//在窗口上显示回形针的角度 将弧度转为角度deg(Phi)
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
Disp_message(winId, (((hv_Phi.TupleDeg())).TupleString("3.1f")) + " deg",
"image", hv_Row, hv_Column - 100, "black", "false");
}
}
catch (HalconException HDevExpDefaultException)
{
//ho_Clip.Dispose();
//ho_Dark.Dispose();
//ho_Single.Dispose();
//ho_Selected.Dispose();
//hv_Width.Dispose();
//hv_Height.Dispose();
//hv_UsedThreshold.Dispose();
//hv_Phi.Dispose();
//hv_Area.Dispose();
//hv_Row.Dispose();
//hv_Column.Dispose();
//hv_Length.Dispose();
throw HDevExpDefaultException;
}
finally
{
ho_Clip.Dispose();
ho_Dark.Dispose();
ho_Single.Dispose();
ho_Selected.Dispose();
hv_Width.Dispose();
hv_Height.Dispose();
hv_UsedThreshold.Dispose();
hv_Phi.Dispose();
hv_Area.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
hv_Length.Dispose();
}
}
// Procedures
// External procedures
// Chapter: Graphics / Text
// Short Description: Write one or multiple text messages.
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)
{
// Local control variables
HTuple hv_GenParamName = new HTuple(), hv_GenParamValue = new HTuple();
HTuple hv_Color_COPY_INP_TMP = new HTuple(hv_Color);
HTuple hv_Column_COPY_INP_TMP = new HTuple(hv_Column);
HTuple hv_CoordSystem_COPY_INP_TMP = new HTuple(hv_CoordSystem);
HTuple hv_Row_COPY_INP_TMP = new HTuple(hv_Row);
// Initialize local and output iconic variables
try
{
#region specification
//This procedure displays text in a graphics window.
//
//Input parameters:
//WindowHandle: The WindowHandle of the graphics window, where
// the message should be displayed.
//String: A tuple of strings containing the text messages to be displayed.
//CoordSystem: If set to 'window', the text position is given
// with respect to the window coordinate system.
// If set to 'image', image coordinates are used.
// (This may be useful in zoomed images.)
//Row: The row coordinate of the desired text position.
// You can pass a single value or a tuple of values.
// See the explanation below.
// Default: 12.
//Column: The column coordinate of the desired text position.
// You can pass a single value or a tuple of values.
// See the explanation below.
// Default: 12.
//Color: defines the color of the text as string.
// If set to [] or '' the currently set color is used.
// If a tuple of strings is passed, the colors are used cyclically
// for every text position defined by Row and Column,
// or every new text line in case of |Row| == |Column| == 1.
//Box: A tuple controlling a possible box surrounding the text.
// Its entries:
// - Box[0]: Controls the box and its color. Possible values:
// -- 'true' (Default): An orange box is displayed.
// -- 'false': No box is displayed.
// -- color string: A box is displayed in the given color, e.g., 'white', '#FF00CC'.
// - Box[1] (Optional): Controls the shadow of the box. Possible values:
// -- 'true' (Default): A shadow is displayed in
// darker orange if Box[0] is not a color and in 'white' otherwise.
// -- 'false': No shadow is displayed.
// -- color string: A shadow is displayed in the given color, e.g., 'white', '#FF00CC'.
//
//It is possible to display multiple text strings in a single call.
//In this case, some restrictions apply on the
//parameters String, Row, and Column:
//They can only have either 1 entry or n entries.
//Behavior in the different cases:
// - Multiple text positions are specified, i.e.,
// - |Row| == n, |Column| == n
// - |Row| == n, |Column| == 1
// - |Row| == 1, |Column| == n
// In this case we distinguish:
// - |String| == n: Each element of String is displayed
// at the corresponding position.
// - |String| == 1: String is displayed n times
// at the corresponding positions.
// - Exactly one text position is specified,
// i.e., |Row| == |Column| == 1:
// Each element of String is display in a new textline.
//
//
//Convert the parameters for disp_text.
#endregion
if ((int)((new HTuple(hv_Row_COPY_INP_TMP.TupleEqual(new HTuple()))).TupleOr(
new HTuple(hv_Column_COPY_INP_TMP.TupleEqual(new HTuple())))) != 0)
{
hv_Color_COPY_INP_TMP.Dispose();
hv_Column_COPY_INP_TMP.Dispose();
hv_CoordSystem_COPY_INP_TMP.Dispose();
hv_Row_COPY_INP_TMP.Dispose();
hv_GenParamName.Dispose();
hv_GenParamValue.Dispose();
return;
}
if ((int)(new HTuple(hv_Row_COPY_INP_TMP.TupleEqual(-1))) != 0)
{
hv_Row_COPY_INP_TMP.Dispose();
hv_Row_COPY_INP_TMP = 12;
}
if ((int)(new HTuple(hv_Column_COPY_INP_TMP.TupleEqual(-1))) != 0)
{
hv_Column_COPY_INP_TMP.Dispose();
hv_Column_COPY_INP_TMP = 12;
}
//
//Convert the parameter Box to generic parameters.
hv_GenParamName.Dispose();
hv_GenParamName = new HTuple();
hv_GenParamValue.Dispose();
hv_GenParamValue = new HTuple();
if ((int)(new HTuple((new HTuple(hv_Box.TupleLength())).TupleGreater(0))) != 0)
{
if ((int)(new HTuple(((hv_Box.TupleSelect(0))).TupleEqual("false"))) != 0)
{
//Display no box
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamName = hv_GenParamName.TupleConcat(
"box");
hv_GenParamName.Dispose();
hv_GenParamName = ExpTmpLocalVar_GenParamName;
}
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamValue = hv_GenParamValue.TupleConcat(
"false");
hv_GenParamValue.Dispose();
hv_GenParamValue = ExpTmpLocalVar_GenParamValue;
}
}
}
else if ((int)(new HTuple(((hv_Box.TupleSelect(0))).TupleNotEqual(
"true"))) != 0)
{
//Set a color other than the default.
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamName = hv_GenParamName.TupleConcat(
"box_color");
hv_GenParamName.Dispose();
hv_GenParamName = ExpTmpLocalVar_GenParamName;
}
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamValue = hv_GenParamValue.TupleConcat(
hv_Box.TupleSelect(0));
hv_GenParamValue.Dispose();
hv_GenParamValue = ExpTmpLocalVar_GenParamValue;
}
}
}
}
if ((int)(new HTuple((new HTuple(hv_Box.TupleLength())).TupleGreater(1))) != 0)
{
if ((int)(new HTuple(((hv_Box.TupleSelect(1))).TupleEqual("false"))) != 0)
{
//Display no shadow.
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamName = hv_GenParamName.TupleConcat(
"shadow");
hv_GenParamName.Dispose();
hv_GenParamName = ExpTmpLocalVar_GenParamName;
}
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamValue = hv_GenParamValue.TupleConcat(
"false");
hv_GenParamValue.Dispose();
hv_GenParamValue = ExpTmpLocalVar_GenParamValue;
}
}
}
else if ((int)(new HTuple(((hv_Box.TupleSelect(1))).TupleNotEqual(
"true"))) != 0)
{
//Set a shadow color other than the default.
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamName = hv_GenParamName.TupleConcat(
"shadow_color");
hv_GenParamName.Dispose();
hv_GenParamName = ExpTmpLocalVar_GenParamName;
}
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_GenParamValue = hv_GenParamValue.TupleConcat(
hv_Box.TupleSelect(1));
hv_GenParamValue.Dispose();
hv_GenParamValue = ExpTmpLocalVar_GenParamValue;
}
}
}
}
//Restore default CoordSystem behavior.
if ((int)(new HTuple(hv_CoordSystem_COPY_INP_TMP.TupleNotEqual("window"))) != 0)
{
hv_CoordSystem_COPY_INP_TMP.Dispose();
hv_CoordSystem_COPY_INP_TMP = "image";
}
//
if ((int)(new HTuple(hv_Color_COPY_INP_TMP.TupleEqual(""))) != 0)
{
//disp_text does not accept an empty string for Color.
hv_Color_COPY_INP_TMP.Dispose();
hv_Color_COPY_INP_TMP = new HTuple();
}
//
HOperatorSet.DispText(hv_WindowHandle, hv_String, hv_CoordSystem_COPY_INP_TMP,
hv_Row_COPY_INP_TMP, hv_Column_COPY_INP_TMP, hv_Color_COPY_INP_TMP, hv_GenParamName,
hv_GenParamValue);
hv_Color_COPY_INP_TMP.Dispose();
hv_Column_COPY_INP_TMP.Dispose();
hv_CoordSystem_COPY_INP_TMP.Dispose();
hv_Row_COPY_INP_TMP.Dispose();
hv_GenParamName.Dispose();
hv_GenParamValue.Dispose();
return;
}
catch (HalconException HDevExpDefaultException)
{
hv_Color_COPY_INP_TMP.Dispose();
hv_Column_COPY_INP_TMP.Dispose();
hv_CoordSystem_COPY_INP_TMP.Dispose();
hv_Row_COPY_INP_TMP.Dispose();
hv_GenParamName.Dispose();
hv_GenParamValue.Dispose();
throw HDevExpDefaultException;
}
}
// Chapter: Graphics / Text
// Short Description: Set font independent of OS
public void Set_display_font(HTuple hv_WindowHandle, HTuple hv_Size, HTuple hv_Font,
HTuple hv_Bold, HTuple hv_Slant)
{
// Local control variables
HTuple hv_OS = new HTuple(), hv_Fonts = new HTuple();
HTuple hv_Style = new HTuple(), hv_Exception = new HTuple();
HTuple hv_AvailableFonts = new HTuple(), hv_Fdx = new HTuple();
HTuple hv_Indices = new HTuple();
HTuple hv_Font_COPY_INP_TMP = new HTuple(hv_Font);
HTuple hv_Size_COPY_INP_TMP = new HTuple(hv_Size);
// Initialize local and output iconic variables
try
{
//This procedure sets the text font of the current window with
//the specified attributes.
//
//Input parameters:
//WindowHandle: The graphics window for which the font will be set
//Size: The font size. If Size=-1, the default of 16 is used.
//Bold: If set to 'true', a bold font is used
//Slant: If set to 'true', a slanted font is used
//
hv_OS.Dispose();
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.Dispose();
hv_Size_COPY_INP_TMP = 16;
}
if ((int)(new HTuple(((hv_OS.TupleSubstr(0, 2))).TupleEqual("Win"))) != 0)
{
//Restore previous behavior
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_Size = ((1.13677 * hv_Size_COPY_INP_TMP)).TupleInt()
;
hv_Size_COPY_INP_TMP.Dispose();
hv_Size_COPY_INP_TMP = ExpTmpLocalVar_Size;
}
}
}
else
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_Size = hv_Size_COPY_INP_TMP.TupleInt()
;
hv_Size_COPY_INP_TMP.Dispose();
hv_Size_COPY_INP_TMP = ExpTmpLocalVar_Size;
}
}
}
if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("Courier"))) != 0)
{
hv_Fonts.Dispose();
hv_Fonts = new HTuple();
hv_Fonts[0] = "Courier";
hv_Fonts[1] = "Courier 10 Pitch";
hv_Fonts[2] = "Courier New";
hv_Fonts[3] = "CourierNew";
hv_Fonts[4] = "Liberation Mono";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("mono"))) != 0)
{
hv_Fonts.Dispose();
hv_Fonts = new HTuple();
hv_Fonts[0] = "Consolas";
hv_Fonts[1] = "Menlo";
hv_Fonts[2] = "Courier";
hv_Fonts[3] = "Courier 10 Pitch";
hv_Fonts[4] = "FreeMono";
hv_Fonts[5] = "Liberation Mono";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("sans"))) != 0)
{
hv_Fonts.Dispose();
hv_Fonts = new HTuple();
hv_Fonts[0] = "Luxi Sans";
hv_Fonts[1] = "DejaVu Sans";
hv_Fonts[2] = "FreeSans";
hv_Fonts[3] = "Arial";
hv_Fonts[4] = "Liberation Sans";
}
else if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual("serif"))) != 0)
{
hv_Fonts.Dispose();
hv_Fonts = new HTuple();
hv_Fonts[0] = "Times New Roman";
hv_Fonts[1] = "Luxi Serif";
hv_Fonts[2] = "DejaVu Serif";
hv_Fonts[3] = "FreeSerif";
hv_Fonts[4] = "Utopia";
hv_Fonts[5] = "Liberation Serif";
}
else
{
hv_Fonts.Dispose();
hv_Fonts = new HTuple(hv_Font_COPY_INP_TMP);
}
hv_Style.Dispose();
hv_Style = "";
if ((int)(new HTuple(hv_Bold.TupleEqual("true"))) != 0)
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_Style = hv_Style + "Bold";
hv_Style.Dispose();
hv_Style = ExpTmpLocalVar_Style;
}
}
}
else if ((int)(new HTuple(hv_Bold.TupleNotEqual("false"))) != 0)
{
hv_Exception.Dispose();
hv_Exception = "Wrong value of control parameter Bold";
throw new HalconException(hv_Exception);
}
if ((int)(new HTuple(hv_Slant.TupleEqual("true"))) != 0)
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_Style = hv_Style + "Italic";
hv_Style.Dispose();
hv_Style = ExpTmpLocalVar_Style;
}
}
}
else if ((int)(new HTuple(hv_Slant.TupleNotEqual("false"))) != 0)
{
hv_Exception.Dispose();
hv_Exception = "Wrong value of control parameter Slant";
throw new HalconException(hv_Exception);
}
if ((int)(new HTuple(hv_Style.TupleEqual(""))) != 0)
{
hv_Style.Dispose();
hv_Style = "Normal";
}
hv_AvailableFonts.Dispose();
HOperatorSet.QueryFont(hv_WindowHandle, out hv_AvailableFonts);
hv_Font_COPY_INP_TMP.Dispose();
hv_Font_COPY_INP_TMP = "";
for (hv_Fdx = 0; (int)hv_Fdx <= (int)((new HTuple(hv_Fonts.TupleLength())) - 1); hv_Fdx = (int)hv_Fdx + 1)
{
hv_Indices.Dispose();
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
hv_Indices = hv_AvailableFonts.TupleFind(
hv_Fonts.TupleSelect(hv_Fdx));
}
if ((int)(new HTuple((new HTuple(hv_Indices.TupleLength())).TupleGreater(
0))) != 0)
{
if ((int)(new HTuple(((hv_Indices.TupleSelect(0))).TupleGreaterEqual(0))) != 0)
{
hv_Font_COPY_INP_TMP.Dispose();
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
hv_Font_COPY_INP_TMP = hv_Fonts.TupleSelect(
hv_Fdx);
}
break;
}
}
}
if ((int)(new HTuple(hv_Font_COPY_INP_TMP.TupleEqual(""))) != 0)
{
throw new HalconException("Wrong value of control parameter Font");
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
{
HTuple
ExpTmpLocalVar_Font = (((hv_Font_COPY_INP_TMP + "-") + hv_Style) + "-") + hv_Size_COPY_INP_TMP;
hv_Font_COPY_INP_TMP.Dispose();
hv_Font_COPY_INP_TMP = ExpTmpLocalVar_Font;
}
}
HOperatorSet.SetFont(hv_WindowHandle, hv_Font_COPY_INP_TMP);
hv_Font_COPY_INP_TMP.Dispose();
hv_Size_COPY_INP_TMP.Dispose();
hv_OS.Dispose();
hv_Fonts.Dispose();
hv_Style.Dispose();
hv_Exception.Dispose();
hv_AvailableFonts.Dispose();
hv_Fdx.Dispose();
hv_Indices.Dispose();
return;
}
catch (HalconException HDevExpDefaultException)
{
hv_Font_COPY_INP_TMP.Dispose();
hv_Size_COPY_INP_TMP.Dispose();
hv_OS.Dispose();
hv_Fonts.Dispose();
hv_Style.Dispose();
hv_Exception.Dispose();
hv_AvailableFonts.Dispose();
hv_Fdx.Dispose();
hv_Indices.Dispose();
throw HDevExpDefaultException;
}
}
#endregion