第八届泰迪杯准备阶段心得 B题绝缘子 -图像数据处理

图像预处理方面

  • 图像数据的收集阶段
    • GitHub数据
      • 调用百度AI图像处理中的主体识别AIP+CV2 grabCut算法实现自主识别并切割出绝缘子串
      • PhotoShop的妙用
      • 裁切出来的绝缘子主体图像使用二值法模拟生成掩模图

图像数据的收集阶段

GitHub数据

绝缘子数据集
这个github数据集上拥有自爆绝缘子以及完整绝缘子的图片。
优点:数据量很大,而且有对应绝缘子坐标的xml文件。
缺点:数据集普遍分辨率较低,而且可以明显的看到这些数据集是经过数据增强的,而且没有对应原图的掩模图。对于我们二次提取绝缘子的完整子串有很大的难度。

调用百度AI图像处理中的主体识别AIP+CV2 grabCut算法实现自主识别并切割出绝缘子串

百度AI主体识别入口

在上方链接中注册好应用之后就按照新手教程的指导调用他的接口实现自主识别主体并返回对应信息,信息是存储在字典dict中,读取结果的时候要特别小心。

from aip import AipImageClassify

""" 你的 APPID AK SK """
APP_ID = '你的 App ID'
API_KEY = '你的 Api Key'
SECRET_KEY = '你的 Secret Key'

client = AipImageClassify(APP_ID, API_KEY, SECRET_KEY)
""" 读取图片 """
def get_file_content(filePath):
    with open(filePath, 'rb') as fp:
        return fp.read()

image = get_file_content(filePath)

""" 调用图像主体检测 """
client.objectDetect(image);

""" 如果有可选参数 """
options = {}
options["with_face"] = 0

""" 带参数调用图像主体检测 """
a = client.objectDetect(image, options)##赋值的对象是client.objectDetect不是client

print(a['result'])

然后通过接口返回的数据让grabcut获得对应坐标的信息之后就可以进行主体裁切了

!!!
下方代码经由文章出处改动增加多层循环方便批量处理
!!!

下方代码并没有嵌入百度AIP,读者需要自行添加到for里面,并且改动rect的值。

import numpy as np
import cv2
from aip import AipImageClassify
import os
    
     
#鼠标事件的回调函数
def on_mouse(event,x,y,flag,param):        
    global rect
    global leftButtonDowm
    global leftButtonUp
    
    #鼠标左键按下
    if event == cv2.EVENT_LBUTTONDOWN:
        rect[0] = x
        rect[2] = x
        rect[1] = y
        rect[3] = y
        leftButtonDowm = True
        leftButtonUp = False
        
    #移动鼠标事件
    if event == cv2.EVENT_MOUSEMOVE:
        if leftButtonDowm and  not leftButtonUp:
            rect[2] = x
            rect[3] = y        
  
    #鼠标左键松开
    if event == cv2.EVENT_LBUTTONUP:
        if leftButtonDowm and  not leftButtonUp:
            x_min = min(rect[0],rect[2])
            y_min = min(rect[1],rect[3])
            
            x_max = max(rect[0],rect[2])
            y_max = max(rect[1],rect[3])
            
            rect[0] = x_min
            rect[1] = y_min
            rect[2] = x_max
            rect[3] = y_max
            leftButtonDowm = False      
            leftButtonUp = True


for i in range(1,2,1):       
    first_path = "C:\\001.jpg"    
    if(os.path.exists(first_path)==0):
        continue
    #读入图片
    print(str(i)+"*")
    img = cv2.imread(first_path)    
    x, y = img.shape[0:2]
    img_test1 = cv2.resize(img, (int(y / 4), int(x / 4)))
    #掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果
    mask = np.zeros(img_test1.shape[:2],np.uint8)    
    #背景模型,如果为None,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5;
    bgdModel = np.zeros((1,65),np.float64)
    #fgdModel——前景模型,如果为None,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5;
    fgdModel = np.zeros((1,65),np.float64)
    #用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
    rect = [0,0,0,0]      
    #鼠标左键按下
    leftButtonDowm = False
    #鼠标左键松开
    leftButtonUp = True    
    #指定窗口名来创建窗口
    cv2.namedWindow('img') 
    #设置鼠标事件回调函数 来获取鼠标输入
    cv2.setMouseCallback('img',on_mouse)
    #cv2.resizeWindow('img', 1280, 720)
    #显示图片
    cv2.imshow('img',img_test1)


    while cv2.waitKey(2) == -1:
        #左键按下,画矩阵
        if leftButtonDowm and not leftButtonUp:  
            img_copy = img_test1.copy()
            #在img图像上,绘制矩形  线条颜色为green 线宽为2
            cv2.rectangle(img_copy,(rect[0],rect[1]),(rect[2],rect[3]),(0,255,0),2)  
            #显示图片
            #cv2.namedWindow('img',cv2.WINDOW_NORMAL) 
            cv2.imshow('img',img_copy)
        
#         左键松开,矩形画好 
        elif not leftButtonDowm and leftButtonUp and rect[2] - rect[0] != 0 and rect[3] - rect[1] != 0:
    #转换为宽度高度
            rect[2] = rect[2] - rect[0]
            rect[3] = rect[3] - rect[1]
            rect_copy = tuple(rect.copy())   
            rect = [0,0,0,0]
             #物体分割
            cv2.grabCut(img_test1,mask,rect_copy,bgdModel,fgdModel,10,cv2.GC_INIT_WITH_RECT)
            
            mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
            img_show = img_test1*mask2[:,:,np.newaxis]
            #显示图片分割后结果
            cv2.imshow('grabcut',img_show)
            save_path = "F:\\3.jpg"
            cv2.imwrite(save_path, img_show)
            #显示原图
            cv2.imshow('img',img_test1)  
    cv2.waitKey(0)
    cv2.destroyAllWindows()

遇到的问题

  1. 调用百度AIP时候错将client作为对象输出结果,正确的对象是client.objectDetect(image, options)
  2. cv2在使用imshow显示图片之后还需加上cv2.waitKey(0)这行代码不然无法正常显示图片
  3. 在代码中我还使用了cv2.resize这个函数,因为原图实在是太大了,需要缩小尺寸才能通过cv2.imshow窗口预览,并且图像过大会导致grabcut加载速度变得异常缓慢。
  4. 补个坑,详细介绍grabcut
  5. cv2路径中不允许有中文路径

PhotoShop的妙用

grabcut裁剪出来的绝缘子主体仍然有一部分杂边出现,这时候可以使用PhotoShop中的油漆桶进行修改,油漆桶自带颜色范围检测,每次点击只会使与点击区域颜色相近且处于周围的像素块发生改变。

裁切出来的绝缘子主体图像使用二值法模拟生成掩模图

通过前面几步我们可以得到如下效果:
第八届泰迪杯准备阶段心得 B题绝缘子 -图像数据处理_第1张图片
接下来由于背景全黑,所以我们可以利用非黑即白的想法,将除了黑之外的颜色转化为白色。即可得到掩模图。

!!!
以下代码源自百度,我忘记存作者文章地址了,如有知道的小伙伴请告诉我!!
!!!

from PIL import Image
import os
for j in range(1,51,1):
    if(j<10):
        first_path = 'F:\\turning\\00'+str(j)+'.jpg'
        
    else:
        first_path = 'F:\\turning\\0'+str(j)+'.jpg'
    # 模式L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。
    
    if(os.path.exists(first_path)==0):
        continue
    img = Image.open(first_path)
    Img = img.convert('L')
    #Img.save(first_path)
    
    # 自定义灰度界限,大于这个值为黑色,小于这个值为白色
    threshold = 10
 
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    
    
    if(j<10):
        path = 'C:\\00'+str(j)+'.jpg'
        
    else:
        path = 'C:\\\0'+str(j)+'.jpg'
    # 图片二值化
    photo = Img.point(table, '1')
    photo.save(path)

效果如下:
第八届泰迪杯准备阶段心得 B题绝缘子 -图像数据处理_第2张图片
可以尝试调整threshold对阈值进行调节

以上是我对初期图像处理的一些总结。

你可能感兴趣的:(泰迪杯)