pythonopencvimage-processingcomputer-visiondiplib

How to detect pits on smart card contact pins using diplib


During the smart card manufacture process, a probe stucks could leave pits on contact pins. I try to use dip.tophat and dip.HysteresisThreshold to extract the pits, this works but found more local height outside or near the edge of the contact pins. How could I filter those extra local height out?

import diplib as dip

height = dip.ImageRead('my2.png')

local_height = dip.Tophat(height, 9)

dip.viewer.ShowModal(local_height)

inselbergs = dip.HysteresisThreshold(local_height, 20, 30)

dip.viewer.ShowModal(inselbergs)

dip.viewer.ShowModal(dip.Overlay(height, inselbergs))

labels = dip.Label(inselbergs, minSize = 3, maxSize = 20)

dip.viewer.ShowModal(dip.Overlay(height, labels))

dip.ImageWrite(dip.Overlay(height, labels), 'out.jpg')

result = dip.MeasurementTool.Measure(labels, features=['Size', 'Center'])
print(result)

two stucks probe leave the pits on contact pins two stucks probe leave the pits on contact pins

I want to filter out extra local height I want to filter out extra local height

Also I would like to detect scratchs on the pin contacts Also I would like to detect scratchs on the pin contacts

import diplib as dip

height = dip.ImageRead('my2.png')

vess = dip.FrangiVesselness(height, sigmas=0.6, polarity='black')
dip.viewer.ShowModal(vess)

myout = dip.HysteresisThreshold(vess,0.2,0.4)
dip.viewer.ShowModal(dip.Overlay(height, myout))

labels = dip.Label(myout, minSize = 3, maxSize = 30)
dip.viewer.ShowModal(dip.Overlay(height, labels))

dip.ImageWrite(dip.Overlay(height, labels), 'out2.jpg')

dip::FrangiVesselness find so many lines dip::FrangiVesselness find so many lines

I want to filter out the extra local height outside or near the pin contacts, I want to filter out the extra lines which didn't represent the scratchs. The pre-punched hole on bottom left of each module is so problematic, it must be filtered out also


Solution

  • You need to detect the contact areas first, then limit the other detections to be within those areas

    So I take the advice from the author of diplib, also I enhance the light source and change the background from white to black. The following is what I did so far Image produced from a 130Mp GiGE camera

    
    import diplib as dip
    import math
    
    img = dip.ImageRead('my2.png')
    obj = dip.Threshold(img)[0]
    
    dip.viewer.Show(obj)
    
    obj3 = dip.Erosion(obj, 6)
    
    # This operator stablize the ultimate result tremendously
    obj3 = dip.ClosingByReconstruction(obj3, 6)
    
    dip.viewer.Show(obj3)
    
    obj4 = img.Copy()
    obj4.Mask(obj3)
    
    dip.viewer.Show(obj4)
    
    lab = dip.Label(obj3, minSize = 1700, maxSize = 6000)
    msr = dip.MeasurementTool.Measure(lab,img,['Size'])
    print(msr)
    
    local_height = dip.Tophat(obj4, 9)
    
    # I don't know why Tophat produce some strange inselbergs, so filter them all
    mask = local_height < 100
    dip.viewer.Show(mask)
    
    local_height = local_height.Copy()
    local_height.Mask(mask)
    
    dip.viewer.Show(local_height)
    inselbergs = dip.HysteresisThreshold(local_height, 20, 50)
    
    dip.viewer.Show(dip.Overlay(obj4, inselbergs))
    
    labels = dip.Label(inselbergs, minSize = 3, maxSize = 16)
    dip.viewer.Show(dip.Overlay(obj4, labels))
    
    # The result is greatly improved, but I still have to find the pre-punched holes as the mask to filter out the glitchs near them
    dip.ImageWrite(dip.Overlay(obj4, labels), 'out3.jpg')
    
    

    This result is not bad, although extra work still needed to filter out the spots near the pre-punched hole area. Diplib is awesome,provide the nice abstraction to manipulate images.But at the price of relative slow processing time compare to OpenCV enter image description here

    At last, I leave some code to find the pre-punched holes mask

    import diplib as dip
    import math
    
    img = dip.ImageRead('my2.png')
    
    # Extract object
    obj = dip.Threshold(img)[0]
    
    dip.viewer.Show(obj)
    
    obj3 = dip.Dilation(obj, 5)
    
    dip.viewer.Show(~obj3)
    
    obj4 = dip.EdgeObjectsRemove(~obj3)
    dip.viewer.Show(obj4)
    
    lab = dip.Label(obj4, minSize = 500, maxSize = 700)
    dip.viewer.Show(lab)
    
    msr = dip.MeasurementTool.Measure(lab,img,['Size'])
    print(msr)
    
    

    I am a Haskeller, ultimately I would like to integrate the code to my own machine vision framework. So I rewrite the algorithm in C++ so that I can easily integrated using inline-c-cpp framwork

    
    #include "diplib.h"
    #include "dipviewer.h"
    #include "diplib/simple_file_io.h"
    #include "diplib/linear.h"       // for dip::Gauss()
    #include "diplib/segmentation.h" // for dip::Threshold()
    #include "diplib/regions.h"      // for dip::Label()
    #include "diplib/measurement.h"
    #include "diplib/mapping.h"      // for dip::ContrastStretch() and dip::ErfClip()
    #include "diplib/binary.h"
    #include "diplib/testing.h"
    #include "diplib/generation.h"
    #include "diplib/statistics.h"
    #include "diplib/morphology.h"
    #include "diplib/detection.h"
    #include "diplib/display.h"
    
    int main() {
    
      dip::testing::Timer timer;
      dip::Image circle;
    
      timer.Reset();
    
      auto a = dip::ImageRead("./my2.jpg");
    
      dip::Image b, c, d, e, f, g, labels;
      dip::Threshold(a, b);
    
      c = dip::ClosingByReconstruction(b,6);
    
      d = dip::Erosion(c,1);
    
      f = a.Copy();
    
      f.At(~d).Fill(0);
    
      e = dip::FrangiVesselness(f, {0.67});
      
      dip::viewer::Show(e);
    
      g = dip::HysteresisThreshold(e,0.12,0.4);
    
      dip::viewer::Show(g);
    
      labels = dip::Label(g, 0, 3, 30);
    
      dip::MeasurementTool measurementTool;
      auto msr = measurementTool.Measure(labels, f, {"Radius"});
    
      std::cout << msr << '\n';
    
      dip::Image feature = dip::ObjectToMeasurement(labels, msr[ "Radius" ]);
    
      // filter out extra regions through Radius.StdDev
      labels.At( feature[3] > 0.0002 ) = 0; 
    
      dip::viewer::Show(dip::Overlay(a,labels));
    
      dip::viewer::Spin();
    
      return 0;
    }
    
    

    The following is the C++ make file

    cmake_minimum_required(VERSION 2.8)
    project( detection )
    find_package( DIPlib REQUIRED )
    include_directories( ${OpenCV_INCLUDE_DIRS} )
    add_executable( detection detection.cpp )
    target_link_libraries( detection DIP DIPviewer ${OpenCV_LIBS} )