Here is a nice solution implemented in MATLAB.
Here is my answer using Python and OpenCV (translation of the original MATLAB code).
In JAVA there are no vectorized matrix operations, so the solution relies on OpenCV.
Since the solution is based on the Python implementation, it finds all the non-red pixels (instead of finding the red pixels).
The HSV ranges of the non-red pixels are taken from the original solution:
int minHue = 21;
int maxHue = 169; //340/2-1
Saturation and Value includes the full range of [0, 255].
Important modification from your posted code:
grey
image should be in BGR (3 channels) format before using grey.copyTo(result, mask)
, because the destination image result
has 3 color channels.
We may convert grey to BGR, and than using copyTo
:
Mat grey_as_bgr = new Mat();
Imgproc.cvtColor(grey, grey_as_bgr, Imgproc.COLOR_GRAY2BGR); //Convert from Gray to BGR where R=G=B (we need 3 color channels).
grey_as_bgr.copyTo(result, mask);
JAVA code sample:
package myproject;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
class Sample {
static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
public static void main(String[] args) {
//The following JAVA code is partly based on the following Python and OpenCV code:
//Python code (my answer): https://stackoverflow.com/a/71542681/4926757
//The Python code is a conversion from the original MATLAB code:
//Original MATLAB code: https://stackoverflow.com/questions/4063965/how-can-i-convert-an-rgb-image-to-grayscale-but-keep-one-color
Mat image = Imgcodecs.imread("src/playground/input.png"); //Read input image //img = cv2.imread('src/playground/input.png')
Mat hsv = new Mat();
Imgproc.cvtColor(image, hsv, Imgproc.COLOR_BGR2HSV); //Convert the image to HSV color space. //hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
//Instead of finding red pixels, find all the non-red pixels.
//Note: in OpenCV hue range is [0,179]) The original MATLAB code is 360.*hsvImage(:, :, 1), when hue range is [0, 1].
int minHue = 21; //non_red_idx = (h > 20//2) & (h < 340//2) # Select "non-red" pixels (divide the original MATLAB values by 2 due to the range differences).
int maxHue = 169; //340/2-1;
int minSaturation = 0;
int maxSaturation = 255;
int minValue = 0;
int maxValue = 255;
//Create a mask of all non-red pixels
Mat mask = new Mat();
Core.inRange(hsv, new Scalar(minHue, minSaturation, minValue), new Scalar(maxHue, maxSaturation, maxValue), mask);
Mat grey = new Mat();
Mat grey_as_bgr = new Mat();
Imgproc.cvtColor(image, grey, Imgproc.COLOR_BGR2GRAY); //Convert image from BGR to Grey
Imgproc.cvtColor(grey, grey_as_bgr, Imgproc.COLOR_GRAY2BGR); //Convert from Gray to BGR where R=G=B (we need 3 color channels).
Mat result = image.clone(); //Clone image, and store in result
grey_as_bgr.copyTo(result, mask); //Copy the non-red pixels from grey_as_bgr to result (the red pixels are kept unmodified).
Imgcodecs.imwrite("src/playground/output.png", result); //Save the result
}
}
Output:
