0
点赞
收藏
分享

微信扫一扫

机器视觉1:图像预处理与瑕疵检测

Raow1 2022-05-23 阅读 35

自行拍摄鸡蛋破损照片,简述拍摄照片时应注意的事项(包括相机角度,背景设置,光线环境,拍摄距离等);简述图片预处理和瑕疵检测时的考虑与方案设计。

1.拍照注意事项
①相机角度尽量在鸡蛋的正上方约15cm处;
②调整镜头,使鸡蛋位于拍摄图像中心;
③背景颜色为黑色;
④背景需展平且干净,不可有褶皱或其他干扰色点;
⑤不宜在灯光正下方拍摄,易存在阴影;
⑥在光源照射下,不要使背景过亮或过暗,拍摄时易反光或无区分度;
2. 算法大致步骤
①图像亮度调整、去噪、锐化
首先,将原RGB图像转为灰度图像。
为提高图像对比度,采用分段线性变换的方法,但在此次实验中,提高图像对比度后效果较差或作用不大,故不采取。
由于在对图像求边界时,易遭受鸡蛋外壳表面纹状和背景脉冲噪声的影响,同时为保证图像细节,采用中值滤波的方法,对灰度图像进行去噪,然后利用拉普拉斯滤波进行线性锐化,以中和中值滤波使细节淡化的部分。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
②高频强调、求边界、去除蛋壳边界
在对图像求边界的同时进行高频强调,以增强图像中变化率较大的区分度,即边界或轮廓部分。
由于在对连通区域进行标记时,常受到鸡蛋外壳的干扰,即使标记时取第二大连通域。出于对检测本身的考虑,鸡蛋壳以外的部分无需考虑在其中,故在去除鸡蛋壳的同时,将蛋壳以外的像素全部置零。具体方法是,将去噪、锐化后的原图像转化为二值图像,先执行腐蚀操作,使其缩减一圈,然后与求边界后的图像相点乘。
在这里插入图片描述在这里插入图片描述
③形态学处理
由于求边界后的二值图像轮廓边缘较细,易将原本连通的区域边缘部分分开,从而造成检测中的误差问题。为此,采用形态学操作中的膨胀、闭运算、腐蚀操作使边缘轮廓部分稍微加粗。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
④ Blob法求连通域、按面积标注破损位置
采用八连接标注连通域,并计算连通域的个数,每个连通域的面积、中心点以及外接矩形。然后对面积进行排序,找到最大的破损标注位置。如果连通域大于3个,则只标出3个最大的连通域;若连通域小于三个,则全部用其外接矩形标出。
在这里插入图片描述

⑤计算检测精度
首先利用Ostu(最大类间方差法)求使图像二值化的最佳全局阈值,利用此阈值将原灰度图像转为二值图像,得到前景分割的结果M;然后分别设定检测阈值和标注阈值。通过手动标注得到标注的模板G,再由④中的检测结果A计算检测破损率和实际破损率。
在计算bad和badg之前,为保证检测区域是否为真实破损区域,先将标注的检测结果与手动标注的模板进行点乘操作,运算后,留下的轮廓才是真正的破损区域。
在这里插入图片描述
前景分割手动标注的破损模板
检测结果与标注模板的重合部分
计算准确率时,需要设置检测阈值th和标注阈值thg,且按以下标准计算TP(被预测为好蛋的坏蛋)、FP(被预测为好蛋的好蛋)、FN、TN;
在这里插入图片描述最后通过公式求得准确率。
在这里插入图片描述
经计算,得出准确率为1。

代码文件

放在一个文件夹即可运行。
1.主函数main.m

%% 1.读取图像并转为灰度值
clc;clear;close all;
input_path = './data/dataset/';  %原图路径
output_path = './data/result/';  %检测结果保存路径
labelmoban_path = './data/label_moban/';  %标注模板路径
outlabel_path = './data/result_label/';%检测结果带标签路径
%% 将标注好的图像二值化为标注模板
label_path = './data/label/';    %原图标签路径
biaozhumoban(label_path,labelmoban_path);
%% 生成检测结果+计算检测精度
egg_pre(input_path,output_path);  %预测图像输出在/result/
[Accuracy,bad] = detect_precision(input_path,output_path,labelmoban_path);
disp('准确率:');disp(Accuracy);

2.函数文件biaozhumoban.m

function [] = biaozhumoban(label_path,labelmoban_path)
files_label = dir([label_path '*.jpg']);
l = length(files_label);
for i = 1:l
    I_label = imread([label_path files_label(i).name]);
    Sign_I = imbinarize(im2gray(I_label),0.95);
    imwrite(Sign_I,[labelmoban_path files_label(i).name(1:end-9) 'label_moban.jpg']);
end

3.函数文件egg_pre.m

function [] = egg_pre(input_path,output_path)
files = dir([input_path '*.jpg']);
leng = length(files);
for k = 1:leng
    I = rgb2gray(imread([input_path files(k).name]));
    %figure,imshow(I);title('原图')
    %中值滤波去除脉冲噪声,保持图像细节
    mid_I = medfilt2(I,[5,5]);  %5*5的中值滤波窗口
    % figure,imshow(mid_I);title('平滑滤波')
    % 4.锐化滤波
    %拉普拉斯滤波线性锐化
    mask = [1,1,1;1,-8,1;1,1,1];
    L_I = mid_I-imfilter(mid_I,mask,'replicate');
    % figure,imshow(L_I);title('拉普拉斯滤波')
    %非线性锐化:锐化因邻域平均导致的模糊图像:sobel
    % 5.高频强调+求边界
    ed = edge(L_I,'canny',0.18);
    % ed = edge(L_I,'sobel',0.04);
    % figure,imshow(ed);title('高频强调+边界')
    
    %去除蛋壳边界
    I2 = imbinarize(L_I);% 转为二值图像
    ed1 = bwmorph(I2,'erode',1);    %腐蚀
    ed = ed .* ed1;
    % figure,imshow(ed)
 
    % 6.形态学处理
    expe = bwmorph(ed,'dilate',2);  
    %figure,imshow(expe);title('膨胀');
    %闭运算:先膨胀后腐蚀
    BW = bwmorph(expe,'close',1);
    %figure,imshow(BW);title('闭运算')
    
    corr = bwmorph(BW,'erode',1);
    % figure,imshow(corr);title('腐蚀');
    
    BW = corr;
    figure,imshow(BW);title('最终结果');
    % 7.Blob法
    %1.求连通域,标注破损位置
    [L,num] = bwlabel(BW,8);
    %L   : 标记矩阵
    %num : 连接分量的总数
    %BW  : 输入的二值图像
    %8   : 指定期望连接方式(4,8)
    
    %2.计算连通域个数,每个连通域面积、中心点、外接矩形
    stats = regionprops(L,'basic');
    
    %stats[Area,Centriod,BoungingBox]
    %连通域面积、中心点、外接矩形
    
    %3.按照连通域面积大小进行排序
    N = size(stats,1);
    for i=1:N-1
        for j=1:N-i
            if stats(j).Area < stats(j+1).Area
                tmp = stats(j);
                stats(j) = stats(j+1);
                stats(j+1) = tmp;
            end
        end
    end
    
    %4.对符合要求的连通域画标记
    if num >= 3        %如果连通区域大于等于3个,只取前三个最大值
        for i=1:3
            boundingbox1 = stats(i).BoundingBox; 
            x = boundingbox1(1);
            y = boundingbox1(2);
            width_x = boundingbox1(3);
            width_y = boundingbox1(4);
            pos = [x y width_x width_y];
            rectangle('Position',pos,'EdgeColor','r');
        end
    else            %如果连通区域小于3个,全取
        for j = 1:num
            boundingbox1 = stats(j).BoundingBox;  
            x = boundingbox1(1);
            y = boundingbox1(2);
            width_x = boundingbox1(3);
            width_y = boundingbox1(4);
            pos = [x y width_x width_y];
            rectangle('Position',pos,'EdgeColor','r');
        end
    end
    imwrite(BW,[output_path files(k).name(1:end-4) '_pre.jpg']);  %保存
end
end

4.函数文件detect_precision.m

function [accuracy,bad] = detect_precision(input_path,output_path,labelmoban_path)
files = dir([input_path '*.jpg']);
leng = length(files);
% 9.计算检测精度
th = 2;    %检测阈值
thg = 5;    %标注阈值
%检测准确率
bad = zeros(leng,2);
FN=0;TP=0;TN=0;FP=0;
for j = 1:leng
    %a)求鸡蛋mask,大津法阈值+二值化
    gray_I = rgb2gray(imread([input_path files(j).name]));
    level = graythresh(gray_I);  %全局阈值
    M = imbinarize(gray_I,level);  %前景分割结果
    %figure,imshow(M),title('前景分割结果');
    M = uint8(M);
    I_pre = imread([output_path strcat(files(j).name(1:end-4),'_pre.jpg')]);%I_pre为检测效果
    groundtruth = imread([labelmoban_path strcat(files(j).name(1:end-4),'_label_moban.jpg')]);
    %groundtruth:标签模板
    
    %将检测结果与实际标注模板相与后,存在部分即为检测真实部分
    I_pre = I_pre .* groundtruth;
    %figure,imshow(I_pre);title('检测结果.*标注模板')
    
    %1.定义基本变量
    bad(j,1) = sum(sum(M.*I_pre))./sum(sum(M));  %检测破损率
    bad(j,2) = sum(sum(M.*groundtruth) ./ sum(sum(M))); %实际破损率
        if bad(j,2)<thg && bad(j,1)>th
            FN = FN+1;
        end
        if bad(j,2)<thg && bad(j,1)<th
            TP = TP+1;
        end
        if bad(j,2)>thg && bad(j,1)>th
            TN = TN+1;
        end
        if bad(j,2)>thg && bad(j,1)<th
            FP = FP+1;
        end
end
accuracy = (TP+TN)/(TP+TN+FP+FN);
举报

相关推荐

0 条评论