halcon缺陷检测-印刷品检测(差异化模型),键盘字符缺陷检测

前言

在实际项目中,印刷品缺陷检测是缺陷检测中的难点项目。通常印刷品检测往往具备缺陷小,缺陷所在位置不固定,出现少印或者多印的情况。并且由于产线原因,大量的印刷品在视野中的大小并不是完全一致的,可能出现细微的歪斜,亮度差异等多种不确定的因素。
所以在印刷品检测时,常用的blob分析+差值算法,往往不能满足实际的要求。所以使用差异化模型,对图像区域进行训练,在可靠的精度下,仍然可以达到极快的检测速度。

1:halcon程序

************************************创建训练图像和训练模型***************************
dev_get_window (WindowHandle)
*初始化区域尺寸
ImageSizeWidth1:=[]
ImageSizeHeight1:=[]
*获取20个ROI的区域
Row1:=[394.115, 397.311, 390.92, 512.34, 515.536, 512.34, 630.565, 633.76, 630.565, 748.79, 755.18, 755.18, 173.642, 259.914, 263.109, 173.642, 263.109, 263.109, 493.169, 585.831, 681.689]
Row2:=[465.388, 472.192, 472.192, 590.417, 593.612, 590.417, 708.642, 711.837, 710.033, 830.062, 830.062, 826.867, 219.766, 318.82, 312.429, 222.962, 315.624, 318.82, 545.683, 641.541, 735.399]
Column1:=[341.424, 485.187, 628.95, 344.618, 481.992, 616.171, 335.034, 472.408, 616.171, 341.424, 475.603, 616.171, 200.855, 127.376, 280.724, 756.739, 683.261, 830.218, 827.024, 830.218, 830.218]
Column2:=[424.487, 565.055, 705.624, 434.071, 565.055, 705.624, 424.487, 568.25, 708.818, 421.292, 568.25, 708.818, 296.697, 220.024, 373.371, 842.997, 766.324, 922.866, 920.255, 916.476, 919.671]

list_files ('D:/2024Work/work/4.2/键盘160/键盘160', ['files','follow_links'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
*先根据模板匹配,将所要识别的区域矫正在图像中心,便于绘制ROI   
read_shape_model ('D:/模板正面.shm',ShapeModelID)
get_shape_model_contours (ModelContours, ShapeModelID, 1)
find_scaled_shape_model (Image, ShapeModelID, rad(0), rad(90), 0.9, 1.1, 0.1, 1, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Scale, Score)

get_image_size (Image, Width, Height)
vector_angle_to_rigid (Row, Column , Angle ,Height/2,Width/2-200,0, HomMat2D)
affine_trans_image (Image, ImageAffineTrans, HomMat2D, 'constant', 'false')
    
*****************绘制区域ROI*************
* for j := 0 to 20 by 1
*     draw_rectangle1 (WindowHandle, Row12, Column12, Row22, Column22)
*     Row1[j]:=Row12
*     Row2[j]:=Row22
*     Column1[j]:=Column12
*     Column2[j]:=Column22
* endfor
*********************************************

*初始化被测试区域的区域大小  
Row111:=[]
Column111:=[]
Row112:=[]
Colum112:=[]

* affRow:=[]
* affColumn:=[]
* affPhi:=[]
for i := 0 to 20 by 1
    gen_rectangle1 (ROI_0, Row1[i], Column1[i], Row2[i], Column2[i])
    reduce_domain (ImageAffineTrans, ROI_0, ImageReduced3)
    crop_domain (ImageReduced3, ImagePart1)
    binary_threshold (ImagePart1, Region, 'max_separability', 'light', UsedThreshold)
    area_center (Region, Area, Row3, Column3)
    smallest_rectangle1 (Region, Row11, Column11, Row21, Column21)

  


    
*     Row3:=(Row11+Row21)/2
*     Column3:=(Column11+Column21)/2
*     affRow[i]:=[Row3]
*     affColumn[i]:=[Column3]
    

    Row111[i]:=[Row11]
    Column111[i]:=[Column11]
    Row112[i]:=[Row21]
    Colum112[i]:=[Column21]
    *绘制比二值化选中区域更大一些的矩形区域,用于训练模板
    gen_rectangle1 (Rectangle, Row11-1, Column11-1, Row21+1, Column21+1)
    reduce_domain (ImagePart1, Rectangle, ImageReduced1)
    crop_domain (ImageReduced1, ImagePart2)
    
    *由于差异化模板需要保持每个输入图像的大小保持一致
    *所以将第一个训练图像作为基准,提取每个图像的尺寸,便于后续图像进行矫正
    get_image_size (ImagePart2, Width1, Height1)
    if (Index!=0)
        zoom_image_size (ImagePart2, ImagePart2, ImageSizeWidth1[i], ImageSizeHeight1[i], 'constant')
    else
        ImageSizeWidth1[i]:=Width1
        ImageSizeHeight1[i]:=Height1
    endif

    *创建文件夹,并将训练图像保存在文件夹中,便于后续提取训练
    file_exists ('D:/2024Work/work/4.2/键盘160/键盘160/'+i, FileExists)
if (not(FileExists))
    make_dir('D:/2024Work/work/4.2/键盘160/键盘160/'+i) 
endif
write_image (ImagePart2, 'bmp', 0, 'D:/2024Work/work/4.2/键盘160/键盘160/'+i+'/'+Index)
endfor


*创建模型数组,对每个区域进行单独的创建模型
    varModelID:=[]
for Index1 := 0 to 20 by 1
    *根据我们所需要的区域尺寸,创建对应的差异化模型
    create_variation_model (ImageSizeWidth1[Index1], ImageSizeHeight1[Index1], 'byte', 'standard', varModelID1)
    *读取对应文件夹的所有图像
    list_files ('D:/2024Work/work/4.2/键盘160/键盘160/'+Index1, ['files','follow_links'], ImageFiles)
    tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
    for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
    
    *训练模型
    train_variation_model (Image, varModelID1)
    *设置模型的最小灰度差值为60,差异化为2
    prepare_variation_model (varModelID1, 60, 2)
    *显示模型图案,用于检查
    get_variation_model (Image, VarImage, varModelID1)
    dev_display (VarImage)
    endfor
   varModelID[Index1]:=varModelID1
endfor
*对创建好的模型数组,逐一写入文件夹中。待使用时提取
for Index2 := 0 to 20 by 1
    write_variation_model (varModelID[Index2], 'D:/2024Work/work/4.2/键盘160/键盘160/var/'+Index2+'.var')
endfor
    
   stop ()
  
endfor



******************************************对训练模型进行测试******************************
*初始化所有检测区域的尺寸
ImageSizeWidth1:=[30, 40, 35, 33, 33, 45, 52, 38, 56, 37, 28, 28, 53, 43, 44, 29, 41, 50, 22, 41, 34]
ImageSizeHeight1:=[62, 62, 62, 61, 61, 62, 61, 61, 62, 56, 60, 36, 24, 42, 35, 29, 32, 34, 32, 46, 42]
*初始化检测区域ROI的位置参数
Row1:=[394.115, 397.311, 390.92, 512.34, 515.536, 512.34, 630.565, 633.76, 630.565, 748.79, 755.18, 755.18, 173.642, 259.914, 263.109, 173.642, 263.109, 263.109, 493.169, 585.831, 681.689]
Row2:=[465.388, 472.192, 472.192, 590.417, 593.612, 590.417, 708.642, 711.837, 710.033, 830.062, 830.062, 826.867, 219.766, 318.82, 312.429, 222.962, 315.624, 318.82, 545.683, 641.541, 735.399]
Column1:=[341.424, 485.187, 628.95, 344.618, 481.992, 616.171, 335.034, 472.408, 616.171, 341.424, 475.603, 616.171, 200.855, 127.376, 280.724, 756.739, 683.261, 830.218, 827.024, 830.218, 830.218]
Column2:=[424.487, 565.055, 705.624, 434.071, 565.055, 705.624, 424.487, 568.25, 708.818, 421.292, 568.25, 708.818, 296.697, 220.024, 373.371, 842.997, 766.324, 922.866, 920.255, 916.476, 919.671]
*初始化差异化模型数组,用于存放读取的全部模型
varmodel:=[]
*将全部模型进行读取并存放在数组中
for Index1 := 0 to 20 by 1
    read_variation_model ('D:/2024Work/work/4.2/键盘160/键盘160/var/'+Index1+'.var', ModelID)
     varmodel[Index1]:=ModelID
endfor
*读取产品模板匹配的模板
read_shape_model ('D:/模板正面.shm',ShapeModelID)

list_files ('D:/2024Work/work/4.2/键盘160/键盘160', ['files','follow_links'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
for Index := 0 to |ImageFiles| - 1 by 1
    
    read_image (Image, ImageFiles[Index])
*********************
 rgb1_to_gray (Image, Image2)
*进行模板匹配。寻找图中的形状,并将所要检测的区域矫正到图像中心
find_scaled_shape_model (Image2, ShapeModelID, rad(0), rad(90), 0.9, 1.1, 0.1, 1, 0.5, 'least_squares', 0, 0.9, Row9, Column9, Angle9, Scale, Score)
get_image_size (Image, Width, Height)
vector_angle_to_rigid (Row9, Column9 , Angle9 ,Height/2,Width/2-200,0, HomMat2D1)
affine_trans_image (Image2, ImageAffineTrans, HomMat2D1, 'constant', 'false')

for i := 0 to 20 by 1
    *根据ROI的参数,获取到图像区域,并对图像区域进行裁切
    gen_rectangle1 (ROI_0, Row1[i], Column1[i], Row2[i], Column2[i])
    reduce_domain (ImageAffineTrans, ROI_0, ImageReduced4)
    crop_domain (ImageReduced4, ImagePart)
    binary_threshold (ImagePart, Region1, 'max_separability', 'light', UsedThreshold1)
    smallest_rectangle1 (Region1, Row12, Column12, Row22, Column22)
    *根据图像区域对图像进行二次裁切,使得图像满足差异化模型
    gen_rectangle1 (Rectangle1, Row12-1, Column12-1, Row22+1, Column22+1)
    reduce_domain (ImagePart, Rectangle1, ImageReduced2)
    crop_domain (ImageReduced2, ImagePart3)
    *根据差异化模型的区域大小,对裁切的区域进行缩放,将区域的大小与差异化模型进行相匹配
    zoom_image_size (ImagePart3, ImageZoom, ImageSizeWidth1[i], ImageSizeHeight1[i], 'constant')
    *将区域应用在差异化模型中
    compare_variation_model (ImageZoom, RegionDiff, varmodel[i])
    *将差异部分的区域分割开来
	connection (RegionDiff, ConnectedRegions)
 *将区域面积大于30的作为缺陷进行输出
    select_shape (ConnectedRegions, SelectedRegions1, 'area', 'and', 30, 10000000)
    dev_display (ImagePart3)
    dev_display (SelectedRegions1)
    stop ()
endfor
endfor

2:halcon程序解析

2.1创建训练模型和训练图像

2.1.1图像矫正

可以预先创建好模板后,直接读取模板文件,然后进行图像仿射变换将图像区域矫正到图像的中央,便于后续绘制ROI。
其中需要注意,矫正后的图像应该保持每个字符识别的区域都要可见。

read_shape_model ('D:/模板正面.shm',ShapeModelID)
get_shape_model_contours (ModelContours, ShapeModelID, 1)
find_scaled_shape_model (Image, ShapeModelID, rad(0), rad(90), 0.9, 1.1, 0.1, 1, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Scale, Score)

get_image_size (Image, Width, Height)
vector_angle_to_rigid (Row, Column , Angle ,Height/2,Width/2-200,0, HomMat2D)
affine_trans_image (Image, ImageAffineTrans, HomMat2D, 'constant', 'false')
    

矫正前
在这里插入图片描述
矫正后
在这里插入图片描述

2.1.2绘制ROI

对图像上的每个需要识别的单独区域进行ROI的绘制

*****************绘制区域ROI*************
 for j := 0 to 20 by 1
     draw_rectangle1 (WindowHandle, Row12, Column12, Row22, Column22)
     Row1[j]:=Row12
     Row2[j]:=Row22
     Column1[j]:=Column12
     Column2[j]:=Column22
 endfor
*********************************************

在绘制ROI时,应该将ROI尽可能的覆盖到全部识别的区域,比识别的区域稍大,但又不会覆盖到其他区域的大小,并且尽可能的大一些可以有效的防止矫正精度不够时,仍然可以准确的识别的所需要识别的区域。
在这里插入图片描述
将绘制完成后的区域坐标复制并粘贴到程序中,后续就不需要重复的绘制ROI
在这里插入图片描述

2.1.3生成被检测的区域

通过对绘制好的ROI进行裁剪,使用自动二值化阈值,提取到模型的区域,然后再根据实际物体的大小绘制比实际物体稍大一点的图像作为训练图像进行输出

    gen_rectangle1 (ROI_0, Row1[i], Column1[i], Row2[i], Column2[i])
    reduce_domain (ImageAffineTrans, ROI_0, ImageReduced3)
    crop_domain (ImageReduced3, ImagePart1)
    binary_threshold (ImagePart1, Region, 'max_separability', 'light', UsedThreshold)
    area_center (Region, Area, Row3, Column3)
    smallest_rectangle1 (Region, Row11, Column11, Row21, Column21)

    *绘制比二值化选中区域更大一些的矩形区域,用于训练模板
    gen_rectangle1 (Rectangle, Row11-1, Column11-1, Row21+1, Column21+1)
    reduce_domain (ImagePart1, Rectangle, ImageReduced1)
    crop_domain (ImageReduced1, ImagePart2)

在这里插入图片描述

2.1.4保存图像

对首张图像,我们需要获取到第一张图像的全部被识别的区域的大小,并对后续的所有图像区域进行对应的缩放。差异化模型需要保证所有测试图像和训练图像都保持同一个大小。

*由于差异化模板需要保持每个输入图像的大小保持一致
    *所以将第一个训练图像作为基准,提取每个图像的尺寸,便于后续图像进行矫正
    get_image_size (ImagePart2, Width1, Height1)
    if (Index!=0)
        zoom_image_size (ImagePart2, ImagePart2, ImageSizeWidth1[i], ImageSizeHeight1[i], 'constant')
    else
        ImageSizeWidth1[i]:=Width1
        ImageSizeHeight1[i]:=Height1
    endif

    *创建文件夹,并将训练图像保存在文件夹中,便于后续提取训练
    file_exists ('D:/2024Work/work/4.2/键盘160/键盘160/'+i, FileExists)
if (not(FileExists))
    make_dir('D:/2024Work/work/4.2/键盘160/键盘160/'+i) 
endif
write_image (ImagePart2, 'bmp', 0, 'D:/2024Work/work/4.2/键盘160/键盘160/'+i+'/'+Index)

在这里插入图片描述
同样,将所有获取到的尺寸保存的数组中。

2.1.5训练和保存模型


*创建模型数组,对每个区域进行单独的创建模型
    varModelID:=[]
for Index1 := 0 to 20 by 1
    *根据我们所需要的区域尺寸,创建对应的差异化模型
    create_variation_model (ImageSizeWidth1[Index1], ImageSizeHeight1[Index1], 'byte', 'standard', varModelID1)
    *读取对应文件夹的所有图像
    list_files ('D:/2024Work/work/4.2/键盘160/键盘160/'+Index1, ['files','follow_links'], ImageFiles)
    tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
    for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
    
    *训练模型
    train_variation_model (Image, varModelID1)
    *设置模型的最小灰度差值为60,差异化为2
    prepare_variation_model (varModelID1, 60, 2)
    *显示模型图案,用于检查
    get_variation_model (Image, VarImage, varModelID1)
    dev_display (VarImage)
    endfor
   varModelID[Index1]:=varModelID1
endfor
*对创建好的模型数组,逐一写入文件夹中。待使用时提取
for Index2 := 0 to 20 by 1
    write_variation_model (varModelID[Index2], 'D:/2024Work/work/4.2/键盘160/键盘160/var/'+Index2+'.var')
endfor    

2.2测试模型

2.2.1初始化参数和模型

检测区域的尺寸,ROI位置参数,差异化模型,模板均可以在前面进行复制粘贴即可

******************************************对训练模型进行测试******************************
*初始化所有检测区域的尺寸
ImageSizeWidth1:=[30, 40, 35, 33, 33, 45, 52, 38, 56, 37, 28, 28, 53, 43, 44, 29, 41, 50, 22, 41, 34]
ImageSizeHeight1:=[62, 62, 62, 61, 61, 62, 61, 61, 62, 56, 60, 36, 24, 42, 35, 29, 32, 34, 32, 46, 42]
*初始化检测区域ROI的位置参数
Row1:=[394.115, 397.311, 390.92, 512.34, 515.536, 512.34, 630.565, 633.76, 630.565, 748.79, 755.18, 755.18, 173.642, 259.914, 263.109, 173.642, 263.109, 263.109, 493.169, 585.831, 681.689]
Row2:=[465.388, 472.192, 472.192, 590.417, 593.612, 590.417, 708.642, 711.837, 710.033, 830.062, 830.062, 826.867, 219.766, 318.82, 312.429, 222.962, 315.624, 318.82, 545.683, 641.541, 735.399]
Column1:=[341.424, 485.187, 628.95, 344.618, 481.992, 616.171, 335.034, 472.408, 616.171, 341.424, 475.603, 616.171, 200.855, 127.376, 280.724, 756.739, 683.261, 830.218, 827.024, 830.218, 830.218]
Column2:=[424.487, 565.055, 705.624, 434.071, 565.055, 705.624, 424.487, 568.25, 708.818, 421.292, 568.25, 708.818, 296.697, 220.024, 373.371, 842.997, 766.324, 922.866, 920.255, 916.476, 919.671]
*初始化差异化模型数组,用于存放读取的全部模型
varmodel:=[]
*将全部模型进行读取并存放在数组中
for Index1 := 0 to 20 by 1
    read_variation_model ('D:/2024Work/work/4.2/键盘160/键盘160/var/'+Index1+'.var', ModelID)
     varmodel[Index1]:=ModelID
endfor
*读取产品模板匹配的模板
read_shape_model ('D:/模板正面.shm',ShapeModelID)

2.2.2测试模型并检测

rgb1_to_gray (Image, Image2)
*进行模板匹配。寻找图中的形状,并将所要检测的区域矫正到图像中心
find_scaled_shape_model (Image2, ShapeModelID, rad(0), rad(90), 0.9, 1.1, 0.1, 1, 0.5, 'least_squares', 0, 0.9, Row9, Column9, Angle9, Scale, Score)
get_image_size (Image, Width, Height)
vector_angle_to_rigid (Row9, Column9 , Angle9 ,Height/2,Width/2-200,0, HomMat2D1)
affine_trans_image (Image2, ImageAffineTrans, HomMat2D1, 'constant', 'false')

for i := 0 to 20 by 1
    *根据ROI的参数,获取到图像区域,并对图像区域进行裁切
    gen_rectangle1 (ROI_0, Row1[i], Column1[i], Row2[i], Column2[i])
    reduce_domain (ImageAffineTrans, ROI_0, ImageReduced4)
    crop_domain (ImageReduced4, ImagePart)
    binary_threshold (ImagePart, Region1, 'max_separability', 'light', UsedThreshold1)
    smallest_rectangle1 (Region1, Row12, Column12, Row22, Column22)
    *根据图像区域对图像进行二次裁切,使得图像满足差异化模型
    gen_rectangle1 (Rectangle1, Row12-1, Column12-1, Row22+1, Column22+1)
    reduce_domain (ImagePart, Rectangle1, ImageReduced2)
    crop_domain (ImageReduced2, ImagePart3)
    *根据差异化模型的区域大小,对裁切的区域进行缩放,将区域的大小与差异化模型进行相匹配
    zoom_image_size (ImagePart3, ImageZoom, ImageSizeWidth1[i], ImageSizeHeight1[i], 'constant')
    *将区域应用在差异化模型中
    compare_variation_model (ImageZoom, RegionDiff, varmodel[i])
    *将差异部分的区域分割开来
	connection (RegionDiff, ConnectedRegions)
 *将区域面积大于30的作为缺陷进行输出
    select_shape (ConnectedRegions, SelectedRegions1, 'area', 'and', 30, 10000000)
    dev_display (ImagePart3)
    dev_display (SelectedRegions1)
    stop ()
endfor

实际检测效果
在这里插入图片描述

3.总结

上面其中重点提到了对ROI的选取。核心的关键在于如何去矫正图像,矫正区域。这个图像,由于已经预先固定在一个指定的区域,所以在检测时可以通过ROI去框选检测。而且每个检测区域有着较大的距离,所以在框选ROI时误差相对会比较的少。
对于上图而言20个检测区域,实际总共检测耗时在70ms左右。检测速度可以达到相当快,并且检测精度高。

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Halcon是一种常用的图像处理软件,可以用于各种缺陷检测任务。在Halcon中,可以使用不同的算法和技术来进行缺陷检测。根据引用\[1\]中提供的实例,Halcon可以用于背景网格产品刮伤缺陷检测、不均匀表面刮伤检测、产品表面三角缺陷检测、产品毛刺检测、产品上凹坑检测、产品周围缺口检测、电路板短路、断路检测、找出所有网格顶点的位置、化妆品标签褶皱检测、皮革纹理表面缺陷检测、手机摄像头图像表面的轻微缺陷检测、网状产品表面破损检测、铣刀刀口破损缺陷检测检测印刷数字是否完整等任务。 根据引用\[2\]中的描述,缺陷检测是一项具有挑战性的任务,需要保证稳定性和精度。传统的算法检测缺陷通常需要进行复杂的调试和参数调整,而且容易出现检测不稳定和误测的情况。机器学习和深度学习成为缺陷检测领域的重要技术难点。机器学习方法通常使用类似MLP的神经网络对缺陷特征进行训练和分类。深度学习方法则需要大量的缺陷样本进行训练,并且需要手动标注缺陷位置,训练周期较长。迁移学习法是一种新兴的方法,可以利用已经训练好的网络模型进行缺陷检测。 在日常工程应用中,Halcon通常使用形状匹配进行定位,但当待匹配物体有较大变形时,形状匹配的结果可能不准确,特别是在塑料产品成形时变形或纺织产品因褶皱而变形的情况下。这时需要采用其他方法来获得精确的定位结果。 综上所述,Halcon可以应用于各种缺陷检测任务,并且可以根据具体情况选择合适的算法和技术来实现精确的检测结果。 #### 引用[.reference_title] - *1* [【愚公系列】2023年04月 Halcon机器视觉-15种常用缺陷检测实例](https://blog.csdn.net/aa2528877987/article/details/129943049)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [基于halcon缺陷检测常用方法与示例总结](https://blog.csdn.net/weixin_50016546/article/details/124981131)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值