Image corrosion and swelling belong to morphological operations, which are a series of image processing operations based on shape. The basic idea of digital morphology is to measure and extract the corresponding shape in the image by using the structural elements with certain shape, so as to achieve the purpose of image analysis and recognition. Image corrosion and expansion are based on the highlighted part (white). Expansion is to expand the highlighted part, similar to “field expansion”, while corrosion is to corrode the highlighted part, similar to “field encroachment”. The application of expansion corrosion is mainly embodied in eliminating noise, dividing independent elements or connecting adjacent elements, searching for obvious maximum and minimum regions in images and finding image gradients.

The image of corrosion

The function of image corrosion is to shrink the target image. The operation effect depends on the size and content of structural elements and the properties of logical operation. Corrosion treatment can be expressed as probing the image with structural elements to find the area in the image where the structural element can be placed. Corrosion is a process in which boundary points are removed and indented. Can be used to eliminate small, meaningless objects.

Corrosion algorithm

  • With structural elements, scan every element of the image;
  • Do it with the structure element and its overlaid binary imagewithOperation;
  • If both are 1, the element in the resulting image is 1. Otherwise 0.
  • Result: the binary image is reduced by one circle

[ dst ( x . y ) = min ( x . y ) : element ( x . y ) indicates 0 src ( x + x . y + y ) ] [\texttt{dst} (x,y) = \min _{(x’,y’): \, \texttt{element} (x’,y’) \ne0 } \texttt{src} (x+x’,y+y’)]

Definition of corrosion

For sets A and B, use B to corrode A, use


A B A\ominus B

Represents and uses


( B ) z (B)_z

Represents the result obtained after B shifts Z. If the translated result is included in A, then we record z point, and the set of all Z points meeting the above conditions is the result of A being corroded by B. Represented by:


A B = z ( B ) z A A\ominus B = | z | (B)_z \subseteq A|

Corrosion diagram

API

public static void erode(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue) 
Copy the code
  • Parameter 1: SRC, the input image to be corrupted, the number of channels of the image can be arbitrary, but the data type of the image must be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F

  • Parameter two: DST, etched output image, with the same size and data type as input image SRC

  • Parameter 3: kernel, the structural element used for the corrosion operation, can be defined by itself or generated using the getStructuringElement() function

  • Parameter 4: Anchor, the location of the center point in the structural element. The default parameter is the geometric center point of the structural element

  • Parameter 5: Iterations, the number of times of corrosion. The default value is 1

  • Parameter 6: borderType, pixel extrapolation select logo

  • Parameter 7: borderValue, the boundary value when using boundary invariant extrapolation

public static Mat getStructuringElement(int shape, Size ksize, Point anchor) 
Copy the code
  • Parameter 1: Shape, the type of structure element

    // C++: enum MorphShapes_c
    public static final int
            CV_SHAPE_RECT = 0,  
            CV_SHAPE_CROSS = 1, 
            CV_SHAPE_ELLIPSE = 2, 
            CV_SHAPE_CUSTOM = 100;
    Copy the code
  • Parameter two: ksize, the size of the structure element

  • Parameter 3: Anchor is the location of the center point. The default parameter is the geometric center point of the structural element

About the shape of the structure

  • CV_SHAPE_RECT: rectangular structure element

[ E i j = 1 ] [E_{ij}=1]
  • CV_SHAPE_CROSS: cruciform structural element

[ E i j = { 1 if   i = anchor.y   o r j = anchor.x 0 otherwise ] [E_{ij} = \begin{cases} 1 & \texttt{if } {i=\texttt{anchor.y } {or } {j=\texttt{anchor.x}}} \\0 & \texttt{otherwise} \end{cases}]
  • CV_SHAPE_ELLIPSE: element of an ellipse structure. Inner ellipse of rectangle.

operation

/** * image corrosion **@author yidong
 * @date2020/6/24 * /
class ErosionActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityErosionBinding
    private lateinit var mBinary: Mat
    private var mFlag = Imgproc.CV_SHAPE_RECT
        set(value) {
            field = value
            doErode(value, mSize.toDouble())
        }
    private var mSize = 3
        set(value) {
            field = value
            doErode(mFlag, value.toDouble())
        }

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_erosion)
        mBinding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar? , progress:Int, fromUser: Boolean) {
                mSize = progress
                Toast.makeText(this@ErosionActivity."value = $progress", Toast.LENGTH_SHORT).show()
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?).{}override fun onStopTrackingTouch(seekBar: SeekBar?).{}})val bgr = Utils.loadResource(this, R.drawable.opencv)
        mBinary = Mat()
        val gray = Mat()
        Imgproc.cvtColor(bgr, gray, Imgproc.COLOR_BGR2GRAY)
        Imgproc.threshold(gray, mBinary, 125.0.255.0, Imgproc.THRESH_BINARY_INV)
        mBinding.ivLena.showMat(mBinary)
        bgr.release()
    }

    override fun onCreateOptionsMenu(menu: Menu?).: Boolean {
        menuInflater.inflate(R.menu.menu_erosion, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        mFlag = when (item.itemId) {
            R.id.erosion_cross -> {
                Imgproc.CV_SHAPE_CROSS
            }
            R.id.erosion_ellipse -> {
                Imgproc.CV_SHAPE_ELLIPSE
            }
            else -> Imgproc.CV_SHAPE_RECT
        }
        return true
    }

    private fun doErode(flag: Int, width: Double) {
        title = "Flag = $flagSize =,${width}X${width}"
        val kernel = Imgproc.getStructuringElement(flag, Size(width, width))
        val result = Mat()
        Imgproc.erode(mBinary, result, kernel)
        GlobalScope.launch(Dispatchers.Main) {
            mBinding.ivResult.showMat(result)
            result.release()
        }
    }
}
Copy the code

The effect

The source code

Github.com/onlyloveyd/…

In addition, you can also search my official account [OpenCV or Android], follow my series of articles and communicate with me.