I am trying to manipulate individual image pixel with OpenCV 3.1 Java. And OpenCV read an Image as byte array. I want to convert color image to gray image without changing the total of the image channels with function Y = R*0.299 + G*0.587 + B*0.114, so the result will still be an RGB image (3 color channels). From my understanding, because the the sum of 0.299 + 0.587 + 0.114 = 1, and although the byte range from -128 to 127, there should be no problem with underflow or overflow, when casting to byte. But the result is weird, because some white area of the image become black, and some black area become white. I assume that underflow or overflow happened. Here is my code:
List<Mat> channels = new ArrayList<>();
Core.split(intImage, channels);
int totalInt = (int)(channels.get(0).total());
byte[] blue = new byte[totalInt];
byte[] green = new byte[totalInt];
byte[] red = new byte[totalInt];
channels.get(0).get(0, 0, blue);
channels.get(1).get(0, 0, green);
channels.get(2).get(0, 0, red);
for (int i = 0; i < totalInt; i++) {
byte s = (byte)(blue[i]*0.114 + green[i]*0.587 + red[i]*0.299);
blue[i] = red[i] = green[i] = s;
}
channels.get(0).put(0, 0, blue);
channels.get(1).put(0, 0, green);
channels.get(2).put(0, 0, red);
Mat gray = new Mat();
Core.merge(channels, gray);
I have try to convert the image to CvType.CV_16S
, which represent the unsigned short, and it worked without problem so far . Convert to CV_8UC3 still in byte. I am worrying about the heap problem, because when i try with int, which is CV_32S, heap error occur with some large image. So here is my question:
- If could, how can I prevent or deal with those overflow/underflow. I am still consider using byte because it will reduce the heap/memory usage.
- If the first is the only option, how can I can convert CV_16S directly to BufferedImage without convert back to the original Mat type, because I am using Swing to display the image.
I found the method to convert from Mat to BufferedImage
as follows:
public BufferedImage toBufferedImage(Mat matrix) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (matrix.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
BufferedImage image = new BufferedImage(matrix.cols(),
matrix.rows(), type);
final byte[] targetPixels =
((DataBufferByte)image.getRaster().getDataBuffer()).getData();
matrix.get(0, 0, targetPixels);
return image;
}
Please explain, what's happening with the byte casting.