Как добавить координаты в сегментации водораздела? - PullRequest
3 голосов
/ 30 апреля 2020

Я разрабатываю приложение, которое удаляет фон изображений в соответствии с координатами, нарисованными на экране пользователем. Пользователь dr aws представляет собой прямоугольник вокруг интересующего изображения. При этом я использую водораздел для сегментирования изображения и удаления фона с изображения. Однако у меня возникают проблемы при вставке координат в алгоритм, чтобы удалить весь фон. На изображении ниже я выбираю только 4 монеты, после сегментации я хочу, чтобы только 4 эти монеты остались на изображении, а остальные исчезли. Однако это не то, что происходит. Может ли кто-нибудь помочь мне сделать этот сегмент удаления на основе региона, переданного пользователем?

enter image description here

Код:

    typealias Coordinates = Pair<Point, Point>    
    private fun extractForegroundFromBackground(coordinates: Coordinates){
    // TODO: Provide complex object that has both path and extension

    val width: Int
    val height: Int
    val rect = Rect(coordinates.first, coordinates.second)
    width = bitmap.getWidth()
    height = bitmap.getHeight()
    val rgba = Mat()
    val gray_mat = Mat()
    val threeChannel = Mat()

    Utils.bitmapToMat(bitmap, gray_mat)

    Imgproc.cvtColor(gray_mat, rgba, Imgproc.COLOR_RGBA2RGB)

    Imgproc.cvtColor(rgba, threeChannel, Imgproc.COLOR_RGB2GRAY)
    Imgproc.threshold(threeChannel, threeChannel, 100.0, 255.0, Imgproc.THRESH_OTSU)

    Imgproc.GaussianBlur(threeChannel, threeChannel, Size(5.0,5.0), 0.0)
    val edges = Mat()
    Imgproc.Canny(threeChannel, edges, 50.0, 200.0)
    val contours: List<MatOfPoint> = ArrayList()
    val hierarchy = Mat()
    Imgproc.findContours(edges, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE)

    val fg = Mat(rgba.size(), CvType.CV_8U)
    Imgproc.erode(threeChannel, fg, Mat(), Point(-1.0, -1.0), 2)

    val bg = Mat(rgba.size(), CvType.CV_8U)
    Imgproc.dilate(threeChannel, bg, Mat(), Point(-1.0, -1.0), 3)
    Imgproc.threshold(bg, bg, 1.0, 127.0, Imgproc.THRESH_BINARY_INV)
    val markers = Mat(rect.size(), CvType.CV_8U, Scalar(0.0))

    val frame = Mat()
    val rectImage = Mat(rgba.size(), CvType.CV_8U)
    Imgproc.rectangle(rectImage, coordinates.first, coordinates.second, Scalar(255.0, 255.0, 255.0), FILLED)
    Log.i("teste,", coordinates.first.toString() + "\n"+ coordinates.second.toString())
    Core.add(fg, bg, markers, rectImage)

    // Start the WaterShed Segmentation :
    val marker_tempo = Mat()
    markers.convertTo(marker_tempo, CvType.CV_32S)

    Imgproc.watershed(rgba, marker_tempo)
    marker_tempo.convertTo(markers, CvType.CV_8U)

    result_Bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)

    Imgproc.applyColorMap(markers, markers, COLORMAP_BONE)
    Utils.matToBitmap(markers, result_Bitmap)

    image.setImageBitmap(result_Bitmap)

    return currentPhotoPath
}
}

Вывод :

image

1 Ответ

2 голосов
/ 07 мая 2020

Самый простой способ - добавить параметр mask в метод add . Вам нужно будет создать изображение прямоугольника rect, чтобы это работало. Используйте толщину = FILLED , чтобы нарисовать заполненный прямоугольник.

val rectImage = Mat(rgba.size(), CvType.CV_8U)
Imgproc.rectangle(rectImage, coordinates, Scalar(255, 255, 255), Imgproc.FILLED)

Core.add(fg, bg, markers, rectImage)

Другие параметры

Вы можете умножить markers изображение по пикселям на изображение прямоугольника. Останутся только пиксели монет, которые находятся внутри прямоугольника.

Однако в этом случае вам нужно убедиться, что умножаемые изображения имеют диапазон [0, 1], но ваши изображения находятся в диапазоне [0, 255]. Таким образом, чтобы это работало, просто делите изображений на 255, затем умножьте их и, наконец, умножьте результат на 255. Существует также метод умножение (Mat src1, Mat src2, Mat dst, двойная шкала) , которое может умножить матрицы и затем умножить результат на 255. Сразу

Другой способ - использовать побитовое и операция. В этом случае вам не нужно конвертировать в диапазон [0, 1].

val rectImage = Mat(rgba.size(), CvType.CV_8U)
Imgproc.rectangle(rectImage, coordinates, Scalar(255, 255, 255), Imgproc.FILLED)

val clippedMarkers = Mat(rgba.size(), CvType.CV_8U)
Core.bitwise_and(markers, rectImage, clippedMarkers)

Еще один вариант - использовать метод copyTo . В качестве третьего параметра используется маска.

val rectImage = Mat(rgba.size(), CvType.CV_8U)
Imgproc.rectangle(rectImage, coordinates, Scalar(255, 255, 255), Imgproc.FILLED)

val clippedMarkers = Mat(rgba.size(), CvType.CV_8U)
Core.copyTo(markers, clippedMarkers, rectImage)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...