OpenCV Java - изменение цвета пикселя - PullRequest
1 голос
/ 20 марта 2020

Я пытаюсь определить способ изменить цвет пикселей моих масок с черного на другой цвет. К сожалению, я не смог определить способ решения этой задачи. По сути, я пытаюсь сделать следующее: mask

и преобразовать черные участки в цвет со значениями (255, 160, 130). Я попробовал несколько методов, чтобы попытаться достичь своей цели. К ним относятся рисовать контуры, setTo и циклически проходить по матрице. К сожалению, все эти попытки потерпели неудачу. Я включил код и полученные результаты ниже.

Метод Draw Contours

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat img = Imgcodecs.imread(
                "C:\\Users\\Hassan\\Documents\\School\\Me\\COMP5900 Y\\Project\\Project\\src\\resources\\face.jpg");
        Mat img_grey = new Mat();
        Mat grad = new Mat(), grad_x = new Mat(), grad_y = new Mat();
        Mat abs_grad_x = new Mat(), abs_grad_y = new Mat();

        int ddepth = CvType.CV_32F;
        int scale = 1;
        int delta = 0;

        Imgproc.GaussianBlur(img, img, new Size(3, 3), 0, 0, Core.BORDER_CONSTANT);
        Imgproc.cvtColor(img, img_grey, Imgproc.COLOR_BGR2GRAY);

        // Apply Sobel
        Imgproc.Sobel(img_grey, grad_x, ddepth, 1, 0, 3, scale, delta, Core.BORDER_DEFAULT);
        Imgproc.Sobel(img_grey, grad_y, ddepth, 0, 1, 3, scale, delta, Core.BORDER_DEFAULT);

        // converting back to CV_8U
        Core.convertScaleAbs(grad_x, abs_grad_x);
        Core.convertScaleAbs(grad_y, abs_grad_y);

        // Total Gradient (approximate)
        Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);

        Photo.fastNlMeansDenoising(grad, grad);
        Imgproc.GaussianBlur(grad, grad, new Size(3, 3), 0, 0, Core.BORDER_CONSTANT);

        // isolate background
        Mat background = new Mat();
        Imgproc.threshold(grad, background, 2, 255, Imgproc.THRESH_BINARY);

        // draw contours
         List<MatOfPoint> contours = new ArrayList<>();
         Mat hierarchy = new Mat();
         Imgproc.findContours(background, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_NONE);
         Mat drawing = Mat.zeros(background.size(), CvType.CV_8UC3);

         List<MatOfPoint> hullList = new ArrayList<>();
         for (MatOfPoint contour : contours) {
             MatOfInt hull = new MatOfInt();
             Imgproc.convexHull(contour, hull);
             Point[] contourArray = contour.toArray();
             Point[] hullPoints = new Point[hull.rows()];
             List<Integer> hullContourIdxList = hull.toList();
             for (int i = 0; i < hullContourIdxList.size(); i++) {
                 hullPoints[i] = contourArray[hullContourIdxList.get(i)];
             }
             hullList.add(new MatOfPoint(hullPoints));
         }

         for (int i = 0; i < contours.size(); i++) {
             Scalar color = new Scalar(255, 160, 130);
             Imgproc.drawContours(drawing, contours, i, color);
             //Imgproc.drawContours(drawing, hullList, i, color );
         }

Draw Contours

Обратите внимание, что я также попытался использовать Imgpro c .RETR_EXTERNAL, но это привело к совершенно черному изображению. Также имя окна High Gui называется «заливка», но я просто забыл обновить имя.

setTo

// replace find and draw contours portion of code above
Mat out = new Mat();
background.copyTo(out);
out.setTo(new Scalar(255, 160, 130), background);

setTo

Итерация по матрице

   // replace draw contours portion of code above
   for (a = 0; a < background.rows(); a++) {
        for(b = 0; b < background.cols(); b++) {
            if(background.get(a,b)[0] == 0) {
                //background.put(a, b, CvType.CV_16F, new Scalar(255, 160, 130));
                double[] data = {255, 160, 130};
                background.put(a, b, data);
            }
        }
    }

iterating over matrix

L oop многообещающе, но я знаю, что это будет неэффективно, так как у меня есть еще 2 маски, которые я также хотел бы обновить. Не могли бы вы предложить эффективный метод, который позволяет мне установить значение для всех трех каналов?

Спасибо

1 Ответ

1 голос
/ 22 марта 2020

Я не уверен, почему вы делаете много операций над изображением, но для меня это выглядит как применение маски и эффективная замена цвета. Поэтому, если есть другие сложности, кроме, пожалуйста, дайте мне знать.

Ниже приведен код, который я искал в Java.

public static void main(String s[]) {
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    Mat matr =Imgcodecs.imread("/home/shariq/Desktop/test.png");
    Mat result = new Mat();
    //create a mask based on range
    Core.inRange(matr, new Scalar(0), new Scalar(50), result);
    Imgcodecs.imwrite("/home/shariq/Desktop/test_in.png", result);
    //apply the mask with color you are looking for, note here scalar is in hsv
    matr.setTo(new Scalar(130,160,255),result);
    Imgcodecs.imwrite("/home/shariq/Desktop/result.png", matr);
}

Мы создаем mask для пикселя значения от 0 до 50 для черного цвета с использованием метода inRange.

Core.inRange(matr, new Scalar(0), new Scalar(50), result);

Эта переменная mask in result применяется к исходной матрице с использованием метода setTo. Значение цвета замены предоставляется в формате HSV через объект Scalar. Новый скаляр (a, b, c) в HSV можно понять в RGB следующим образом: Red = c, Green = b и Blue = a.

matr.setTo(new Scalar(130,160,255),result);

Это довольно быстро по сравнению с итерацией пикселей по одному.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...