Image median threshold in java - java

i am doing the median threshold. The concept is i will insert an color image, then i will use the array.sort to get the median value of each rgb value. then write the new image based on the median value.
Here is the code.
public class medianthreshold{
public static void main(String[] a)throws Throwable{
File f=new File("C:\\Users\\asd\\Documents\\NetBeansProjects\\JavaApplication34\\images.jpg"); //Input Photo File
Color[] pixel=new Color[9];
int[] R=new int[9];
int[] B=new int[9];
int[] G=new int[9];
File output=new File("C:\\Users\\asd\\Documents\\NetBeansProjects\\JavaApplication34\\outputmedian.jpg");
img.setRGB(i,j,new Color(R[4],B[4],G[4]).getRGB());
}
ImageIO.write(img,"jpg",output);
}
}
And i would like to enhance it,make it become black and white image,by putting a condition, if the pixel value of each rgb is less than median, then the value should be 0 (represent white color), else the value become 0xFFFFFF (represent black color). 225x225 is the image width and height.
The problem im facing now is i duno which part i should put to make sure every pixel value will change to 0 or 0xFFFFF in each R[4],G[4],B[4] which represent the median value of rgb. The output image should have 0 and 1 of pixel value which also is a white and black image.

You said median, but you computed the mean. It's ok, it's just an other ways to do an adaptive global thresholding.
In order to make it faster, you should simply use the histogram of the image. It will be faster and simpler to compute the mean or the median value. You can also use the DataBuffer instead of getRGB. Moreover, I strongly advise to use TYPE_3BYTE_BGR images instead of TYPE_INT_RGB.
For the mean, you have code source example in ImageJ.
0/1, 0/0xFF or 0/0xFFFF just depends on the image encoding, so respectively TYPE_BINARY, TYPE_BYTE_GRAY or TYPE_USHORT_GRAY when you work with the BufferedImage.

Related

Invert image pixels after 1 inversion

I have a piece of code, seen below, that I'm using to invert the pixel data of an image. This code works forward on the initial inversion (black becomes white, white becomes black, etc). However, when I take the inverted image file and rerun it through this code to try and get the original image, the values are nowhere near the original and the image has random dark patches and very high contrast.
So tell me, what is a better way to get the inversion of the inversion? Does the below code need tweaking? Is there another way to go about this entirely?
Code:
//bitsStored is the bit depth. In this test, it is 10.
//imageBytes is the pixel data in a byte array
public static short[] invert(int bitsStored) {
short min = min(imageBytes);//custom method. Gets the minimum value in the byte array.
short range = (short) (2 << bitsStored);
short[] holder = new short[imageBytes.length];
for (int i = 0; i < imageBytes.length; i++) {
holder[i] = (short) (range - imageBytes[i] - min);
}
imageBytes = holder;
return imageBytes;
}
Note: The image I'm using has a 16-bit depth but only uses 10-bits for storage.
Let me know if there is any way I can make my question clearer. Thank you!
EDIT: I have an idea. Could this be happening because the min value changes between the first run and the second? I feel like, in concept, the inversion of an inversion should be the original. But in the math, the only number that is the same between the two runs is the range value. So there has to be a better way to do this. I'll continue to think about it, but any insights you guys have on it would be much appreciated.

Java Advanced Imaging: How to get the ImageLayout from a huge image?

I have a couple of huge images which can't be loaded into the memory in whole. I know that the images are tiled and all the methods in the class ImageReader give me plausible non zero return values for
getTileGridXOffset(int),
getTileGridYOffset(int),
getTileWidth(int) and
getTileHeight(int).
My problem now is that I want to read one tile only to avoid having to load the entire image into memory using the ImageReader.readtTile(int, int, int) method. But how do I determine what the valid values for the tile coordinates are?
There is the method getNumXTiles() and getNumYTiles() in the interface RenderedImage but all attempts to create a rendered image from the source results into a out of memory/java heap space error.
The tile coordinates can theoretically be anything and I tried readtTile(0, -1, -1) which also works for a few images I tested.
I also tried to reach the metadata for those images but I didn't find any useful information regarding the image layout.
Is there anyone who can tell me how to get the values for the tile coordinates without having to read the entire image into memory? Is there another way which does not require an instance of ImageLayout?
Thank you very much for your assistance.
First of all, you should check that the ImageReader in question supports tiling for the given image, using the isImageTiled(imageIndex). If it doesn't, you can't expect useful values from the other methods.
Then if it does, all tiles for a given image must be equal in size (but the last tile in each column/the last row may be truncated). This is also the case for all tiled file formats that I know of (ie. TIFF). So, using this knowledge, the number of tiles in both dimensions can be calculated:
// Calculate number of x tiles/y tiles:
int cols = (int) Math.ceil(reader.getWidth(imageIndex) / (double) reader.getTileWidth(imageIndex));
int rows = (int) Math.ceil(reader.getHeight(imageIndex) / (double) reader.getTileHeight(imageIndex));
You can then, loop over the tile indexes (the first tile is always 0,0):
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
BufferedImage tile = reader.readTile(imageIndex, col, row);
// ...do more processing...
}
}
Or, if you only want to get a single tile, you obviously don't need the double for loops. :-)
Note: For ImageReaders/images that don't support tiling, the getTileWidth and getTileHeight methods will just return the same as getWidthand getHeight, respectively.
Also, the readTile API docs says:
If the arguments are out of range, an IllegalArgumentException is thrown. If the image is not tiled, the values 0, 0 will return the entire image; any other values will cause an IllegalArgumentException to be thrown.
This means your example, readtTile(0, -1, -1) should always throw an IllegalArgumentException regardless of the tiling... I suspect some implementations may disregard the tile coordinates completely, and give you the entire image anyway.
PS: The RenderedImage interface could in theory help you. But it would require a special implementation in the ImageReader. In most cases you will just get a normal BufferedImage (which implements RenderedImage), and is a single (1x1) tile.

Having different values between Java and Matlab when Reading a .pgm image

I have to perpare a Trainging set for my Machine Learning Course, in which for a given face image it gives you an answer representing the side of the head ( straight , left , right , up )
For this purpose i need to read a .pgm image file in java and store its pixels in one row of matrix X, and then store the appropriate right answer of this image in a y vector. finally i will save these two arrays in a .mat file.
The problem is when trying to read the pixel values from a (P2 .pgm) image and printing them to console , they don't give identical values with the matlab matrix viewer. what would be the problem?
This is my code:
try{
InputStream f = Main.class.getResourceAsStream("an2i_left_angry_open.pgm");
BufferedReader d = new BufferedReader(new InputStreamReader(f));
String magic = d.readLine(); // first line contains P2 or P5
String line = d.readLine(); // second line contains height and width
while (line.startsWith("#")) { // ignoring comment lines
line = d.readLine();
}
Scanner s = new Scanner(line);
int width = s.nextInt();
int height = s.nextInt();
line = d.readLine();// third line contains maxVal
s = new Scanner(line);
int maxVal = s.nextInt();
for(int i=0;i<30;i++) /* printing first 30 values from the image including spaces*/
System.out.println((byte)d.read());
} catch (EOFException eof) {
eof.printStackTrace(System.out) ;
}
these are the values i get:
50
49
32
50
32
49
32
48
32
50
32
49
56
32
53
57
while this photo is what is indeed in the image from MATLAB Viewer:
(sorry i can't post images because of lack of reputationS)
and this is what you find when you open the .pgm file via notepad++
Take a look at this post in particular. I've experienced similar issues with imread and with Java's ImageIO class and for the longest time, I could not find this link as proof that other people have experienced the same thing... until now. Similarly, someone experienced related issues in this post but it isn't quite the same at what you're experiencing.
Essentially, the reason why images loaded in both Java and MATLAB are different is due to enhancement purposes. MATLAB scales the intensities so the image isn't mostly black. Essentially, the maximum intensity in your PGM gets scaled to 255 while the other intensities are linearly scaled to suit the dynamic range of [0,255]. So for example, if your image had a dynamic range from [0-100] in your PGM file before loading it in with imread, this would get scaled to [0-255] and not be the original scale of [0-100]. As such, you would have to know the maximum intensity value of the image before you loaded it in (by scanning through the file yourself). That is very easily done by reading the third line of the file. In your case, this would be 156. Once you find this, you would need to scale every value in your image so that it is rescaled to what it originally was before you read it in.
To confirm that this is the case, take a look at the first pixel in your image, which has intensity 21 in the original PGM file. MATLAB would thus scale the intensities such that:
scaled = round(val*(255/156));
val would be the input intensity and scaled is the output intensity. As such, if val = 21, then scaled would be:
scaled = round(21*(255/156)) = 34
This matches up with the first pixel when reading it out in MATLAB. Similarly, the sixth pixel in the first row, the original value is 18. MATLAB would scale it such that:
scaled = round(18*(255/156)) = 29
This again matches up with what you see in MATLAB. Starting to see the pattern now? Basically, to undo the scaling, you would need to multiply by the reciprocal of the scaling factor. As such, given that A is the image you loaded in, you need to do:
A_scaled = uint8(double(A)*(max_value/255));
A_scaled is the output image and max_value is the maximum intensity found in your PGM file before you loaded it in with imread. This undoes the scaling, as MATLAB scales the images from [0-255]. Note that I need to cast the image to double first, do the multiplication with the scaling factor as this will most likely produce floating point values, then re-cast back to uint8. Therefore, to bring it back to [0-max_value], you would have to scale in the opposite way.
Specifically in your case, you would need to do:
A_scaled = uint8(double(A)*(156/255));
The disadvantage here is that you need to know what the maximum value is prior to working with your image, which can get annoying. One possibility is to use MATLAB and actually open up the file with file pointers and get the value of the third line yourself. This is also an annoying step, but I have an alternative for you.
Alternative... probably better for you
Alternatively, here are two links to functions written in MATLAB that read and write PGM files without doing that unnecessary scaling, and it'll provide the results that you are expecting (unscaled).
Reading: http://people.sc.fsu.edu/~jburkardt/m_src/pgma_io/pgma_read.m.
Writing: http://people.sc.fsu.edu/~jburkardt/m_src/pgma_io/pgma_write.m
How the read function works is that it opens up the image using file pointers and manually parses in the data and stores the values into a matrix. You probably want to use this function instead of relying on imread. To save the images, file pointers are again used and the values are written such that the PGM standard is maintained and again, your intensities are unscaled.
Your java implementation is printing the ASCII values of the text bytes "21 2 1" etc.
50->2
51->1
32->SPACE
50->2
32->SPACE
51->1
etc.
Some PGM files use a text header, but binary representation for the pixels themselves. These are marked with a different magic string at the beginning. It looks like the java code is reading the file as if it had binary pixels.
Instead, your PGM file has ASCII-coded pixels, where you want to scan a whitespace-separated value for each pixel. You do this the same way you read the width and height.
The debug code might look like this:
line = d.readLine(); // first image line
s = new Scanner(line);
for(int i=0;i<30;i++) /* printing first 30 values from the image including spaces*/
System.out.println((byte)s.nextInt());

How do you compare two Images Edge Descriptors?

Hi i am totally new to image retrieval and i currently implementing a fucntion to retrieve image from database that matche the most the entred image. I have choosen two descriptors via the jfeaturelib library, these two are color histogram and Mpeg7Edege descriptor.
For the RGB color histogram, i found on this very forum that this if you want to compare two of them you only have to do mean of the euclidian distances of each points like this
double dist(vector<double> *histogram1, vector<double> *histogram2) {
double result = 0.0;
for (vector<double>::iterator val1=histogram1->begin(), val2=histogram2->begin();
val1<histogram1->end();
val1++, val2++) {
result += (*val1 - *val2) * (*val1 - *val2);
}
result = sqrt(result);
return result;
}
Does also this apply to the Mpeg7Edge histogram ? I also want to know if this histogram always return the same number of features independently of the image size, because i have tried it with two images and in both cases it'Ls returning 160 feautures.
Sorry, as being the author of JFeatureLib I hadn't watched for issues here (just on the mailinglist).
Sure, you can use the euclidean dist on these vectors. For higher dimensional vectors (10+ or 20+) you might want to consider the cosine dist as it ususally provides better results. But this is something you might simply test in your application.
And yes, the histogram should always yield the same amount of dimensions.

Java Compressing an Image using Arrays 2D to 1D?

I am having trouble with an assignment of mine. I have a class which reads in PGM image files.
I need to create a few classes, the main one being a compression class. I need to compress the PGM (represented by 2D arrays) into a 1D array.
Here are the instructions:
public static short[] compress(short[][])
Is passed a 2D array of shorts which represents an image.
Returns the compressed image as a 1D array of shorts.
That method is my main concern.
Compression idea:
look for horizontal or vertical runs of like pixel values and record the number of times the
pixel value repeated itself.
note by Spektre: this is called RLE run length encoding used by PCX for example
algorithm:
1.Compute the compressed image array using horizontal runs
2.Compute the compressed image array using vertical runs
3.Choose to compress the image uses the best technique for this particular image.
4.Set the Header of image
Set the first and second values of your short [ ] result array to the width and height values.
Set the third value in your short[ ] result array to 1 for horizontal or 2 for vertical compression.
5.Set the image body
The rest of the short [ ] result array is filled with the RLE quantity and value
There are also a few other methods
if anyone wants to help with them:
public static void write(short[], String)
Is passed a 1D array of shorts which represents the compressed image and a desired filename.
Simply write the values to a text file with a .compressed extension added to the filename.
public static short[] read(String)
Is passed a compressed image filename.
Simply reads the values and returns them in a 1D array of shorts.
public static short[][] decompress(short[])
Is passed a 1D array of shorts which represents a compressed image.
Simply decompress the file so that we can display it on the screen
using our showGrayImage( ) code that we already have.
Thanks in advance!

Categories

Resources