I am trying to open grayscale image via OpenCV Mat object and I am getting odd results:
My code:
Mat source = imageLoader.loadImage(srcImage);
Mat mask = imageLoader.loadImage(srcImageMask);
if(!source.size().equals(mask.size())) {
throw new RuntimeException("Size of mask and source differ");
}
//Convert to grayscale format
Mat sourceGrayScaleFormat = ImageConverter.convertToGrayscale(source);
Mat maskGrayScaleFormat = ImageConverter.convertToGrayscale(mask);
int rows = sourceGrayScaleFormat.rows();
int cols = sourceGrayScaleFormat.cols();
for(int row = 0 ; row < rows; ++row) {
for(int col = 0; col < cols; ++col) {
double [] maskPixel = maskGrayScaleFormat.get(row, col);
double [] data = sourceGrayScaleFormat.get(row, col);
if(holeUpperBound > maskPixel[0]/normalizeFactor) {//According to the instructor - we should treat values below 128 values in the mask as hole pixel
data[0] = -1.0; //Treat it a hole
} else {
data[0] = data[0]/255.0;
}
sourceGrayScaleFormat.put(row, col, data );
double [] data1 = sourceGrayScaleFormat.get(row, col);
}
}
I expect that data1 will be equal to data, but is does not. What am I doing wrong?
Edit:
I included an example of k value. Also to be clear I produce three separate arrays from an RGB image . I also include code for loading the image
public static final int[][] SHARPEN = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
Load image
BufferedImage inputImage = ImageIO.read(new File("bridge-rgb.png")); // load the image from this current folder
When I convolute an image in java using 3*3 kernel, the resultant image produced has some of the properties that you would expect from the given kernel but is extremely dark, black being the dominant colour. If I process the image with an identity kernel then identity is returned so I guess that means that Ive selected the correct setting for creating a bufferedImage and hence the problem must be with my convolution algorithm, however I did test the convolution algorithm with a test array and it does seem to be producing accurate output. I wonder could any one make any comment on what I have or point me in the right direction?
for (int j = 0; j < kernelWidth; ++j) {
try {
output+=(input[y-1][x-1+j] * k[0][j]);
counter++;
}catch(Exception e) {
continue;
}
}
for (int j = 0; j < kernelWidth;++j) {
try {
output+=(input[y][x-1+j] * k[1][j]);
counter1++;
}catch(Exception e) {
continue;
}
}
for (int j = 0; j < kernelWidth;++j) {
try {
output+=(input[y+1][x-1+j] * k[2][j]);
counter2++;
}catch(Exception e) {
continue;
}
}
if((output>>bitshiftValue)>255) {
return ((255& 0xff)<<bitshiftValue);
}
else if ((output>>bitshiftValue)<0) {
return 0;
}else {
return output;
} }
I got the arrays to be convoluted with the following method
private static int[][] convertTo2DWithoutUsingGetRGBgreen(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
int[][] result = new int[height][width];
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel + 3 < pixels.length; pixel += pixelLength) {
result[row][col] = ((int) ((pixels[pixel + 2] & 0xff) )<<8);
col++;
if (col == width) {
col = 0;
row++;
}
}
return result;
}
and post convolution I pimply added them together like so
int[][] finalConv = new int[convRedArray.length][convRedArray[0].length];
for(int c =0; c<convRedArray.length;c++) {
for(int p =0;p<convRedArray[0].length;p++) {
finalConv[c][p]=(convBlueArray[c][p])+(convGreenArray[c[p])+(convRedArray[c][p]);
I've been trying to denoise my image by using a median filter as described in this article
I'm only doing one pass until I get this thing working. The result is largely a washed out image, as seen below.
A minimal working version of my code is below:
import java.awt.image.BufferedImage;
import java.util.Arrays;
public class Denoise {
public static void main(String args[]) {
String directory = "C:\\Users\\Speedy Octopus\\Desktop\\Place Car Folders Here\\Original\\15.JPG";
BufferedImage image = ImageUtility.loadImage(directory);
for (int iterationCount = 0; iterationCount < 1; iterationCount++){
for (int i = 1; i < image.getWidth()-1; i++) {
for (int j = 1; j < image.getHeight()-1; j++) {
image.setRGB(i, j, getMedianPixelValue(image, i, j));
}
}
}
String directory2 = "C:\\Users\\Speedy Octopus\\Desktop\\Place Car Folders Here\\Original\\152.JPG";
Controller.saveImage(image, directory2);
}
public static int getMedianPixelValue(BufferedImage image, int i, int j) {
int[] surroundingPixels = new int[8];
int iter = 0;
for (int q = i-1; q<=i+1; q++) {
for (int r = j-1; r<=j+1;r++) {
if (!(q == i && r == j)) {
surroundingPixels[iter] = image.getRGB(q, r);
iter++;
}
}
}
Arrays.sort(surroundingPixels);
int medianIndex = surroundingPixels.length/2;
int medianPixel = surroundingPixels[medianIndex];
return medianPixel;
}
}
As I answered in this question Applying Mean filter on an image using java getRGB "Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB)" so you have to extract and remove the alpha (A) component before you do any comparisons:
pixel=image.getRGB(i, j)&0x00ffffff;
in the media sorting etc
And you can extract the R, G, and B and process them separately, or do the comparison on the whole pixel RGB - you can experiment either way.
I've been trying to convert some opencv C++ code in opencv java and I can't seem to get pixel division to work properly. I take a meanshiftsegmented mat that I convert to grayscale then to 32F.
I then compare the most downsampled then upsampled image (which is comprised of the gray meanshift mat) to the original gray meanshift mat.
I've already read Using get() and put() to access pixel values in OpenCV for Java
however, it and others like it do not work. The error message I am getting is invalid mat type 5. However, even if I were able to see the saliency map I am positive it is wrong. This is because when I pass in image 001.jpg in c++ I am supposed to see the original image + red square around the objects. In java, I am only seeing the original image at the end.
NOTE :
AbstractImageProvider.deepCopy(AbstractImageProvider.matToBufferedImage(Saliency),disp);
Is an API call that works when I attempt to show the original mat, meanShift mat, and the gray meanShift mat. It fails at showing saliency.
c++
I only did a channel split because I was testing out other colorspaces, however in java I only want to use grayscale.
input = MeanShift.clone();
input.convertTo(input, CV_32F);
for(int i = 0; i < Pyramid_Size; i++){DS_Pyramid[i] = input.clone();}
for (int i = 0; i < Pyramid_Size; i++){
for (int k = 0; k <= i; k++){ // Why don't I just downsamplex3 a copy of MeanShift.clone then upsamplex3 that same one? ...
pyrDown (DS_Pyramid[i], DS_Pyramid[i], Size(DS_Pyramid[i].cols/2, DS_Pyramid[i].rows/2));
US_Pyramid[i] = DS_Pyramid[i].clone();
}
for (int j = 0; j <= i; j++){
pyrUp (US_Pyramid[i], US_Pyramid[i], Size(US_Pyramid[i].cols*2, US_Pyramid[i].rows*2));
}
}
top = US_Pyramid[Pyramid_Size - 1].clone(); // most down sampled layer, up sampled.
split(top, top_chs);
split(input.clone(), meanShift_chs); // split into channels result
split(input.clone(), sal_chs); // holder to use for compare
float top_min = 1.0;
float ms_min = 1.0;
for (int i = 0; i < top.rows; i++){ // find the smallest value in both top and meanShift
for (int k = 0; k < top.cols; k++){ // this is so you can sub out the 0 with the min value
for (int j = 0; j < top.channels(); j++){ // later on
float a = top_chs[j].at<float>(i,k);
float b = meanShift_chs[j].at<float>(i,k);
if (a < top_min && a >= 0) {top_min = a;} // make sure you don't have a top_min of zero... that'd be bad.
if (b < ms_min && b >= 0) { ms_min = b;}
}
}
}
for (int i = 0; i < top.rows; i++){
for (int k = 0; k < top.cols; k++){
for (int j = 0; j < top.channels(); j++){
float a,b,c;
a = top_chs[j].at<float>(i,k);
b = meanShift_chs[j].at<float>(i,k);
if (a <= 0){a = top_min;} // make sure you don't divide by zero
if (b <= 0){b = ms_min;} // make sure you really don't divide by zero
if (a <= b){c = 1.0 - a/b;}
else {c = 1.0 - b/a;}
// c = sqrt(c); // makes stuff more salient, but makes noise pop out too
sal_chs[j].at<float>(i,k) = c;
}
}
}
merge(sal_chs, Saliency); // combine into saliency map
imshow("saliency", Saliency);
java
MeanShift = inputImage.clone();
Imgproc.pyrMeanShiftFiltering(MeanShift, MeanShift, MeanShift_spatialRad, MeanShift_colorRad);
Imgproc.cvtColor(MeanShift, MeanShift, Imgproc.COLOR_BGR2GRAY);
MeanShift.convertTo(MeanShift, CvType.CV_32F); // 32F between 0 - 1. ************** IMPORTANT LINE
for (int i = 0; i < PyrSize; i++){
DS_Pyramid.add(new Mat());
UP_Pyramid.add(new Mat());
}
for (int i = 0; i < PyrSize; i++){
DS_Pyramid.set(i, MeanShift);
}
for (int i = 0; i < PyrSize; i++){
for(int k = 0; k <= i; k++){ // At 0 is downsampled once, second twice, third 3 times.
Imgproc.pyrDown(DS_Pyramid.get(i), DS_Pyramid.get(i)); // pyrDown by default img.width / 2 img height / 2
Mat a = new Mat(); // save the sampled down at i
a = DS_Pyramid.get(i);
UP_Pyramid.add(a);
}
for (int j = 0; j <= i; j++){
Imgproc.pyrUp(UP_Pyramid.get(i),UP_Pyramid.get(i));
}
}
top = UP_Pyramid.get(PyrSize-1);
bot = MeanShift.clone();
Saliency = MeanShift.clone();
//http://answers.opencv.org/question/5/how-to-get-and-modify-the-pixel-of-mat-in-java/
//http://www.tutorialspoint.com/java_dip/applying_weighted_average_filter.htm
for (int i = 0; i < top.rows(); i++){
for (int j = 0; j < top.cols(); j++){
int index = i * top.rows() + j;
float[] top_temp = top.get(i, j);
float[] bot_temp = bot.get(i,j);
float[] sal_temp = bot.get(i,j);
if (top_temp[0] <= bot_temp[k]){sal_temp[0] = 1.0f - (top_temp[0]/bot_temp[0]);}
else {sal_temp[0] = 1.0f - (bot_temp[0]/top_temp[0]);}
Saliency.put(i,j, sal_temp);
}
}
AbstractImageProvider.deepCopy(AbstractImageProvider.matToBufferedImage(Saliency),disp);
Found a simple and working solution after a lot of searching. This might help you get past the error- invalid mat type 5
Code:
Mat img = Highgui.imread("Input.jpg"); //Reads image from the file system and puts into matrix
int rows = img.rows(); //Calculates number of rows
int cols = img.cols(); //Calculates number of columns
int ch = img.channels(); //Calculates number of channels (Grayscale: 1, RGB: 3, etc.)
for (int i=0; i<rows; i++)
{
for (int j=0; j<cols; j++)
{
double[] data = img.get(i, j); //Stores element in an array
for (int k = 0; k < ch; k++) //Runs for the available number of channels
{
data[k] = data[k] * 2; //Pixel modification done here
}
img.put(i, j, data); //Puts element back into matrix
}
}
Highgui.imwrite("Output.jpg", img); //Writes image back to the file system using values of the modified matrix
Note: An important point that has not been mentioned anywhere online is that the method put does not write pixels onto Input.jpg. It merely updates the values of the matrix img. Therefore, the above code does not alter anything in the input image. For producing a visible output, the matrix img needs to be written onto a file i.e., Output.jpg in this case. Also, using img.get(i, j) seems to be a better way of handling the matrix elements rather than using the accepted solution above as this helps in visualizing and working with the image matrix in a better way and does not require a large contiguous memory allocation.
public CompressImage(){
}
// compress image method
public static short[] compress(short image[][]){
// get image dimensions
int imageLength = image.length; // row length
int imageWidth = image[0].length; // column length
// convert vertical to horizontal
// store transposed Image
short[][] transposeImage = new short[imageWidth][imageLength];
// rotate by +90
for (int i = 0; i < imageWidth; i++)
{
for (int j = 0; j < imageLength; j++)
{
short temp = image[i][j];
transposeImage[i][j] = image[j][i];
transposeImage[j][i] = temp;
}
}
short temp = image[i][j];
transposeImage[i][j] = image[j][i];
transposeImage[j][i] = temp;
Why are you swapping here? That doesn't make sense - transposeImage is a new matrix, so you don't have to do inplace editing. This is guaranteed to break if imageWidth != imageLength - see if you can figure out why.
And, actually, you're not even swapping. The three lines above are equivalent to:
transposeImage[i][j] = image[j][i];
transposeImage[j][i] = image[i][j];
The body of the nested for loop should really just be:
transposeImage[i][j] = image[j][i];