首页 > 解决方案 > 在android上使用分水岭进行图像分割的问题

问题描述

我正在开发一个使用分水岭算法分割伤口图像的应用程序。为此,用户在伤口的内部区域(感兴趣区域)绘制一条线,并在背景中绘制另一条线。有了这个,我将此绘图的坐标传递给分水岭以执行分割。我在 python 中使用了这段代码来指导我完成这一步。然而,除了没有执行正确的分割之外,黑白图像被保存在与原始图像不同的方向上。在最终图像中,出现的不是分割图像,而是原始图像。我希望有人帮助我纠正这些错误。

代码:

override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
    super.onActivityResult(requestCode, resultCode, resultData)
    if (requestCode == PICK_IMAGE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) {
        tryOpenUri(resultData.data!!, resultData)
        val selectedImage = if (resultData.data != null) {
            resultData.data
        } else {
            resultData.clipData?.getItemAt(0)?.uri
        }
        imageUpload = true
        val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
        val cursor = contentResolver.query(selectedImage!!, filePathColumn, null, null, null)!!
        cursor.moveToFirst()
        currentPhotoPath = cursor.moveToFirst()
            .let { cursor.getString(cursor.getColumnIndex(filePathColumn[0])) }
            .also { cursor.close() }
        cursor.close()

    } else if (requestCode == SAVE_IMAGE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) {
        val outputStream = contentResolver.openOutputStream(resultData.data!!)
        saveToOutputStream(outputStream, defaultPath.getCompressionFormat(), false)
        savedPathsHash = my_canvas.getDrawingHashCode()
        imageUpload = true
    }
}

private fun regionBackground() {

    progressDialog = ProgressDialog(this, R.style.MyDialogTheme)
    progressDialog.setTitle("Wait..")
    progressDialog.setMessage("save the draw...")
    progressDialog.show()
    progressDialog.setCancelable(false)
    //Load the image
    srcOriginal = Imgcodecs.imread(currentPhotoPath)
    //Create a blank image of zeros (same dimension as img)
    //It should be grayscale (1 color channel)
    markers = Mat.zeros(srcOriginal.rows(), srcOriginal.cols(), CvType.CV_32S)
    //This step is manual. The goal is to find the points
    //which create the result we want. I suggest using a
    //tool to get the pixel coordinates.
    //Dictate the background and set the markers to 1
    for (value in 0..my_canvas.pointsToDrawY.size - 1) {
        markers.put(
            my_canvas.pointsToDrawX[value].toInt(),
            my_canvas.pointsToDrawY[value].toInt(),
            1.0
        )
    }
    my_canvas.pointsToDrawXStepTwo.clear()
    my_canvas.pointsToDrawYStepTwo.clear()

   //Log.i("teste", my_canvas.pointsToDrawXStepTwo.toString()+"x"+my_canvas.pointsToDrawYStepTwo)
    Handler().postDelayed({
        progressDialog.dismiss()
    }, 1000)
}

private fun regionOfInterest() {
    //Log.i("teste", my_canvas.pointsToDrawXStepTwo.toString()+"x"+my_canvas.pointsToDrawYStepTwo)
    progressDialog = ProgressDialog(this, R.style.MyDialogTheme)
    progressDialog.setTitle("Wait..")
    progressDialog.setMessage("save the draw...")
    progressDialog.show()
    progressDialog.setCancelable(false)
    //Dictate the area of interest
    //I used different values for each part of the car (for visibility)
    for (value in 0..my_canvas.pointsToDrawYStepTwo.size - 1) {
        markers.put(
            my_canvas.pointsToDrawXStepTwo[value].toInt(),
            my_canvas.pointsToDrawYStepTwo[value].toInt(),
            255.0
        )
    }
    Handler().postDelayed({
        watershedSegmentation()
    }, 1000)

}

private fun watershedSegmentation() {
    //Now we have set the markers, we use the watershed
    //algorithm to generate a marked image
    watershed(srcOriginal, markers)
    //Plot this one. If it does what we want, proceed;
    //otherwise edit your markers and repeat
    val mPath1 = Environment.getExternalStorageDirectory().toString() + "/watershed.png"
    Imgcodecs.imwrite(mPath1,markers)
    //Make the background black, and what we want to keep white
    for (x in 0 until srcOriginal.rows()-1) {
        for (y in 0 until srcOriginal.cols()-1) {
            if(markers.get(x,y).get(0).equals(1.0)){
                markers.put(
                    x,
                    y,
                    0.0
                )
            }
            if((markers[x, y].get(0) == 255.0)){
                markers.put(
                    x,
                    y,
                    255.0
                )
            }
        }
    }
    //Use a kernel to dilate the image, to not lose any detail on the outline
    //I used a kernel of 3x3 pixels
    val marker_tempo = Mat()
    val dilatation = Mat()
    markers.convertTo(marker_tempo, CvType.CV_8U)
    val kernel = Mat(1, 1, CvType.CV_8U)
    //Plot again to check whether the dilation is according to our needs
    //If not, repeat by using a smaller/bigger kernel, or more/less iterations
    Imgproc.dilate(marker_tempo, dilatation, kernel)
    val mPath2 = Environment.getExternalStorageDirectory().toString() + "/dilatation.png"
    Imgcodecs.imwrite(mPath2,dilatation)
    //Now apply the mask we created on the initial image
    Core.bitwise_and(srcOriginal, srcOriginal, dilatation)
    //Plot the final result
    val mPath = Environment.getExternalStorageDirectory().toString() + "/final.png"
    Imgcodecs.imwrite(mPath,dilatation)


    Handler().postDelayed({
        progressDialog.dismiss()
        Toast.makeText(this, "Image segmented!", Toast.LENGTH_SHORT).show()
    }, 1000)


}

原始图像

绘制区域

创建一个零的空白图像(与 img original 的尺寸相同) -为什么它会旋转?以及如何改进这种细分?

输出图像膨胀:

输出图像最终:

能够正确定位此图像缺少什么?

标签: javaandroidopencvkotlinwatershed

解决方案


推荐阅读