* This example shows the use of the operator dyn_threshold for* the segmentation of the raised dots of braille chharacters.* The operator dyn_threshold is especially usefull if the
* background is inhomogeneously illuminated. In this example,* the segmentation with a simple threshold is not possible
* because the brightness of the background increases from
* left to right.*dev_update_off()** Preparation
read_image(Image,'photometric_stereo/embossed_01')get_image_size(Image, Width, Height)dev_get_window(WindowHandle)if(is_handle_elem(WindowHandle)==true)* valid window handle
dev_resize_window_fit_image(Image,0,0,-1,-1)elsedev_open_window_fit_image(Image,0,0,-1,-1, WindowHandle)
endif
set_display_font(WindowHandle,16,'mono','true','false')dev_set_line_width(2)*dev_display(Image)
Message :='Original image'disp_message(WindowHandle, Message,'window',12,12,'black','true')disp_continue_message(WindowHandle,'black','true')stop()** Use a strong mean filter on the image to blur out the braille points
*使用均值滤镜模糊盲文点,因为图像上的点有这不同光亮的
mean_image(Image, ImageMean,59,59)*dev_display(ImageMean)
Message :='Mean filtered image'disp_message(WindowHandle, Message,'window',12,12,'black','true')disp_continue_message(WindowHandle,'black','true')stop()** Compare the original image with the blurred one and determine the
* region where the gray values of the two images differ by more than 15*因只有小点点的光亮色彩不同,设定一个阈值,跟平均值相比交超出15的进行选中
dyn_threshold(Image, ImageMean, RegionDynThresh,15,'not_equal')*dev_display(Image)dev_display(RegionDynThresh)
Message := 'Regions segmented with dyn_threshold'disp_message(WindowHandle, Message,'window',12,12,'black','true')disp_continue_message(WindowHandle,'black','true')stop()** Post-process the found regions
*先膨胀后收缩
closing_circle(RegionDynThresh, RegionClosing,8.5)*进行了开运算
opening_circle(RegionClosing, RegionOpening,6.5)*进行的打散
connection(RegionOpening, ConnectedRegions)*在进行外接圆
smallest_circle(ConnectedRegions, Row, Column, Radius)gen_circle_contour_xld(ContCircle, Row, Column, Radius,0,6.28318,'positive',1)** Show the results
dev_display(Image)dev_set_color('green')dev_display(ContCircle)
Message := 'Results of braille segmentation after morphology'disp_message(WindowHandle, Message,'window',12,12,'black','true')*dev_update_on()
* Read circularly printed bar codes.*dev_update_off()get_system('clip_region', Information)set_system('clip_region','true')read_image(Image,'circular_barcode')get_image_size(Image, Width, Height)dev_close_window()dev_open_window(0,0, Width /2, Height /2,'black', WindowHandle)dev_set_colored(12)dev_display(Image)set_display_font(WindowHandle,14,'mono','true','false')stop()** Segment the ring on the CD that contains the bar code.*找出0到100内的
threshold(Image, Region,0,100)*做闭区间
closing_circle(Region, Region,3.5)*进行打散
connection(Region, ConnectedRegions)*进行圆的宽和高进行过滤
select_shape(ConnectedRegions, Ring,['width','height'],'and',[550,550],[750,750])*进行变成圆
shape_trans(Ring, OuterCircle,'outer_circle')*补齐,除去之前的圆环
complement(Ring, RegionComplement)*进行打散
connection(RegionComplement, ConnectedRegions)*在进行过滤
select_shape(ConnectedRegions, InnerCircle,['width','height'],'and',[450,450],[650,650])* Determine the parameters of the ring that contains the bar code.*得到外圆的中心和半径
smallest_circle(Ring, Row, Column, OuterRadius)*得到内圆的中心和半径
smallest_circle(InnerCircle, InnerRow, InnerColumn, InnerRadius)dev_set_color('green')dev_set_draw('margin')dev_set_line_width(3)dev_display(Image)dev_display(OuterCircle)dev_display(InnerCircle)stop()** Now read the bar code. This is done by computing the polar transformation
* of the ring in the image that contains the bar code.*自己设置的宽度
WidthPolar :=1440*高度是外圆减去内圆,再减去10
HeightPolar :=round(OuterRadius - InnerRadius -10)*进行笛卡尔转换,前面描述的是圆的坐标宽和高,后面描述的就是笛卡尔
polar_trans_image_ext(Image, PolarTransImage, Row, Column,rad(360),0, OuterRadius -5, InnerRadius +5, WidthPolar, HeightPolar,'bilinear')*黑变白,反转
invert_image(PolarTransImage, ImageInvert)** Since the bar code region is quite flat the image height is doubled.*按给定因子缩放图像
zoom_image_factor(ImageInvert, ImageZoomed,1,2,'weighted')*创建bar conde reder的模型
create_bar_code_model([],[], BarCodeHandle)** Bars are small and the contrast is low; therefore the threshold is raised from 0.05 to 0.1.*设置解码参数
set_bar_code_param(BarCodeHandle,'element_size_min',1.5)set_bar_code_param(BarCodeHandle,'meas_thresh',0.3)*查找条码,进行解成128find_bar_code(ImageZoomed, SymbolRegions, BarCodeHandle,'Code 128', DecodedDataStrings)dev_set_window_extents(-1,-1, WidthPolar /2, HeightPolar)dev_display(ImageZoomed)dev_display(SymbolRegions)set_system('clip_region', Information)*设置文字
disp_message(WindowHandle, DecodedDataStrings,'image',10,180,'black','true')stop()** Transform the code region back to the original image and display it.zoom_region(SymbolRegions, SymbolRegions,1,0.5)*将极坐标中的一个区域变换回笛卡尔坐标。
polar_trans_region_inv(SymbolRegions, CodeRegionCircular, Row, Column,rad(360),0, OuterRadius -5, InnerRadius +5, WidthPolar, HeightPolar, Width, Height,'nearest_neighbor')dev_set_window_extents(-1,-1, Width /2, Height /2)dev_display(Image)dev_display(CodeRegionCircular)disp_message(WindowHandle, DecodedDataStrings,'window',12,12,'black','true')
极坐标,光度立体,ocr
* This program demonstrates the use of the photometric stereo technique
* to read imprinted letters on a tire with a low cost setup.* Even if the light sources are not very homogeneous and their
* orientation is only very roughly known, the text can be
* read robustly.** Initialization
PolarTransWidth :=512
PolarTransHeight :=80*dev_close_window()dev_update_off()read_image(Images,'photometric_stereo/tire_0'+[1:4])select_obj(Images, ObjectSelected,1)dev_open_window_fit_image(ObjectSelected,0,0,-1,-1, WindowHandle)set_display_font(WindowHandle,16,'mono','true','false')for Index :=1 to 4 by 1select_obj(Images, ObjectSelected, Index)dev_display(ObjectSelected)disp_message(WindowHandle,'Image '+ Index +'/4','window',12,12,'black','true')wait_seconds(0.5)
endfor
** We donot know the exact orientations of the light sources
*and therefore use only very rough estimates.
Tilts :=[180,270,0,90]
Slants :=[45,45,45,45]** Apply photometric stereo to determine the surface gradient
*用不同的光拍一张照片,使用光度立体
photometric_stereo(Images, HeightField, Gradient, Albedo, Slants, Tilts,'gradient','poisson',[],[])** Calculate the surface curvature for easy segmentation of the letters
*计算曲面曲率以便于字母分割
derivate_vector_field(Gradient, Result,3,'mean_curvature')* Display surface curvature,显示曲面曲率
dev_display(Result)disp_message(WindowHandle,'Surface curvature image','window',12,12,'black','true')disp_continue_message(WindowHandle,'black','true')stop()** Segment text and base line
* The base line of the text is used to align
* the text horizontally(to simplify the OCR)*分段文本和基线
*文本的基线用于对齐
*文本水平显示(简化OCR
*基本的阈值处理
threshold(Result, Region,-0.2,-0.01)connection(Region, ConnectedRegions)*宽度和行进行过滤
select_shape(ConnectedRegions, BaseLine,['width','row'],'and',[600,280],[99999,350])* The base line is converted to an XLD contour
* to determine the radius of the line by fitting
* a circle to the contour
*基线将转换为XLD轮廓
*通过拟合确定直线半径的步骤
*与等高线成圆
gen_contour_region_xld(BaseLine, Contours,'center')*轮廓分割
segment_contours_xld(Contours, ContoursSplit,'lines_circles',8,14,12)*选取多种特征要求的XLD轮廓或多边形
select_contours_xld(ContoursSplit, SelectedContours,'contour_length',500,1e10,-0.5,0.5)*用圆近似XLD轮廓;
fit_circle_contour_xld(ContoursSplit,'ahuber',-1,0,0,3,1, Row, Column, Radius, StartPhi, EndPhi, PointOrder)* Generate circle contours fordebugging(not used)*gen_circle_contour_xld(ContCircle, Row, Column, Radius, StartPhi, EndPhi, PointOrder,1)* If more than 1 contour have been selected,* choose the one with the largest radius
I :=sort_index(Radius)[|Radius|-1]* If the point order of the fitted circle is 'positive',* start and end angle have to be swapped for the polar transform
if(PointOrder[I]=='positive')
Tmp := StartPhi[I]
StartPhi[I]:= EndPhi[I]
EndPhi[I]:= Tmp
endif
* Perform a polar transform on the region
* to align the text with the base line
*极坐标通过圆进行拉直
polar_trans_region(Region, RegionPolarTrans, Row[I], Column[I], StartPhi[I], EndPhi[I], Radius[I]+ PolarTransHeight, Radius[I], PolarTransWidth, PolarTransHeight,'nearest_neighbor')* Select characters from the transformed region
connection(RegionPolarTrans, ConnectedTransRegions)select_shape(ConnectedTransRegions, Letters,['height','width'],'and',[40,20],[60,50])*进行相关位置排序
sort_region(Letters, SortedLetters,'character','true','row')* Create a black & white image from the region for the OCR,从OCR区域创建黑白图像
* 将区域转换为二进制字节图像。
region_to_bin(SortedLetters, BinImage,0,255,512,100)* Read text using a pre-trained classifier
*从文件中读取OCR的.omc分类器,链接:https://www.cnblogs.com/xh6300/p/13392610.htmlread_ocr_class_mlp('Industrial_NoRej', OCRHandle)*使用 OCR 分类器对多个字符进行分类。
do_ocr_multi_class_mlp(SortedLetters, BinImage, OCRHandle, Class, Confidence)** Display results
dev_display(ObjectSelected)area_center(SortedLetters, Area, Row, Column)dev_open_window(60,12, PolarTransWidth, PolarTransHeight +50,'black', WindowHandle1)set_display_font(WindowHandle1,16,'mono','true','false')dev_set_part(-30,0, PolarTransHeight -1+20, PolarTransWidth -1)dev_display(SortedLetters)
DispRow :=mean(Row)+30disp_message(WindowHandle1,'OCR result after polar transform','window',12,12,'black','true')disp_message(WindowHandle1, Class,'image', DispRow, Column -18,'black','true')
* This example demonstrates an application from the pharmaceutical
* industry. The task is to check the content of automatically filled
* blisters. The first image(reference) is used to locate the chambers
* within a blister shape as a reference model, which is then used to
* realign the subsequent images along to this reference shape. Using
* blob analysis the content of each chamber is segmented and finally
* classified by a few shape features.*dev_close_window()dev_update_off()read_image(ImageOrig,'blister/blister_reference')dev_open_window_fit_image(ImageOrig,0,0,-1,-1, WindowHandle)set_display_font(WindowHandle,14,'mono','true','false')dev_set_draw('margin')dev_set_line_width(3)** In the first step, we create a pattern to cut out the chambers in the
* subsequent blister images easily.access_channel(ImageOrig, Image1,1)*阈值分割
threshold(Image1, Region,90,255)shape_trans(Region, Blister,'convex')*角度,用于计算区域的方位信息
orientation_region(Blister, Phi)*找出中心点,和角度
area_center(Blister, Area1, Row, Column)*要放射变换,
vector_angle_to_rigid(Row, Column, Phi, Row, Column,0, HomMat2D)affine_trans_image(ImageOrig, Image2, HomMat2D,'constant','false')*根据得到的中心点和角度对其进行画框
gen_empty_obj(Chambers)for I :=0 to 4 by 1
Row :=88+ I *70for J :=0 to 2 by 1
Column :=163+ J *150gen_rectangle2(Rectangle, Row, Column,0,64,30)concat_obj(Chambers, Rectangle, Chambers)
endfor
endfor
affine_trans_region(Blister, Blister, HomMat2D,'nearest_neighbor')*与原的矩形进行相减得到,
difference(Blister, Chambers, Pattern)union1(Chambers, ChambersUnion)orientation_region(Blister, PhiRef)
PhiRef :=rad(180)+ PhiRef
area_center(Blister, Area2, RowRef, ColumnRef)*** Each image read will be aligned to this pattern and reduced to the area of interest,* which is the chambers of the blister
Count :=6for Index :=1 to Count by 1read_image(Image,'blister/blister_'+ Index$'02')threshold(Image, Region,90,255)connection(Region, ConnectedRegions)select_shape(ConnectedRegions, SelectedRegions,'area','and',5000,9999999)shape_trans(SelectedRegions, RegionTrans,'convex')** Align pattern along blister of image
orientation_region(RegionTrans, Phi)area_center(RegionTrans, Area3, Row, Column)vector_angle_to_rigid(Row, Column, Phi, RowRef, ColumnRef, PhiRef, HomMat2D)affine_trans_image(Image, ImageAffineTrans, HomMat2D,'constant','false')** Segment pills
reduce_domain(ImageAffineTrans, ChambersUnion, ImageReduced)decompose3(ImageReduced, ImageR, ImageG, ImageB)var_threshold(ImageB, Region,7,7,0.2,2,'dark')connection(Region, ConnectedRegions0)closing_rectangle1(ConnectedRegions0, ConnectedRegions,3,3)fill_up(ConnectedRegions, RegionFillUp)select_shape(RegionFillUp, SelectedRegions,'area','and',1000,99999)opening_circle(SelectedRegions, RegionOpening,4.5)connection(RegionOpening, ConnectedRegions)select_shape(ConnectedRegions, SelectedRegions,'area','and',1000,99999)shape_trans(SelectedRegions, Pills,'convex')** Classify segmentation results and display statistics
count_obj(Chambers, Number)gen_empty_obj(WrongPill)gen_empty_obj(MissingPill)for I :=1 to Number by 1select_obj(Chambers, Chamber, I)intersection(Chamber, Pills, Pill)area_center(Pill, Area, Row1, Column1)if(Area >0)min_max_gray(Pill, ImageB,0, Min, Max, Range)if(Area <3800or Min <60)concat_obj(WrongPill, Pill, WrongPill)
endif
elseconcat_obj(MissingPill, Chamber, MissingPill)
endif
endfor
*dev_clear_window()dev_display(ImageAffineTrans)dev_set_color('forest green')count_obj(Pills, NumberP)count_obj(WrongPill, NumberWP)count_obj(MissingPill, NumberMP)dev_display(Pills)if(NumberMP >0or NumberWP >0)disp_message(WindowHandle,'Not OK','window',12,12+600,'red','true')elsedisp_message(WindowHandle,'OK','window',12,12+600,'forest green','true')
endif
*
Message :='# Correct pills: '+(NumberP - NumberWP)
Message[1]:='# Wrong pills : '+ NumberWP
Message[2]:='# Missing pills: '+ NumberMP
*
Colors :=gen_tuple_const(3,'black')if(NumberWP >0)
Colors[1]:='red'
endif
if(NumberMP >0)
Colors[2]:='red'
endif
disp_message(WindowHandle, Message,'window',12,12, Colors,'true')dev_set_color('red')dev_display(WrongPill)dev_display(MissingPill)if(Index < Count)disp_continue_message(WindowHandle,'black','true')
endif
stop()
endfor
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack: 📚…