Working with DrJava - How can I load and alter a jpeg? - java

I'm a complete beginner to programming and I've been trying to figure this out for a while but I'm lost. There's a few different versions of the question, but I think I can figure the rest out after I have one finished code, so I'm just going explain the one. The first part asks to write a program using DrJava that will display an image, wait for a user response, and then reduce the image to have only 4 levels per color channel. It goes on to say this:
"What we want to do is reduce each color channel from the range 0-255 (8 bits) to the range 0-3 (2 bits). We can do this by dividing the color channel value by 64. However, since our actual display still uses 1 byte per color channel, a values 0-3 will all look very much like black (very low color intensity). To make it look right, we need to scale the values back up to the original range (multiply by 64). Note that, if integer division is used, this means that only 4 color channel values will occur: 0, 64, 128 and 192, imitating a 2-bit color palate."
I don't even get where I'm supposed to put the picture and get it to load from. Basically I need it explained like I'm five. Thanks in advance!

Java API documentation will be your best resource.
You can read an BufferedImage via a function ImageIO.read(File).
BufferedImage is an Image, so you can display it a part of a JLabel or JButton.
BufferedImage can be created with different ColorModels, RGB, BGR, ARGB, one byte per colour, indexed colours and so on. Here you want to copy one BufferedImage to another with another Colormodel.
Basically you can create a new BufferedImage with the differing ColorModel, call:
Graphics g = otherImg.getGraphics();
g.drawImage(originalImg, ...);
ImageIO.write(otherImg, ...);

Related

What does the PBO buffer content mean?

I was trying to implement a color picking system by using a PBO(pixel buffer object using OpenGL), and when I finished, I realized the numbers that came out of the PBO when mapped didn't make any sense at all. I made my application render big squares of different colors and the result DID change between these different colors, but even after analyzing the numbers, I can't make sense of it.
For example, clicking on pure red gave me bytes of
(-1,0,0), while pure blue gave (0,0,-1), but against all logic, pure green gives (-1,0,-1), cyan also gives (-1,0,0), and yellow gives (76,-1,0).
Obviously these numbers are wrong, given that two different colors can result in the same byte formation. Shouldn't a fully red color be (127,0,0)?
Here is the code I used for initialization, size 3 because I am only reading one pixel.
pboid = glGenBuffersARB(); //Initialize buffer for pbo
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pboid); //bind buffer
glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, 3,GL_DYNAMIC_READ); //create a pbo with 3 slots
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0); //unbind buffer
And here is the code I used for reading the pixels
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pboid); //Bind the pbo
glReadPixels((int)lastMousePosition.x,(int)lastMousePosition.y,1,1, GL_RGB, GL_UNSIGNED_BYTE, 0); //Read 1 pixel
ByteBuffer colorBuffer = glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY_ARB); //Map the buffer so we can read it
for(int x = 0; x < colorBuffer.limit(); x++)
{
System.out.println("color byte: " + colorBuffer.get(x)); //Print out the color byte
}
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_EXT); //Unmap the buffer so it can be used again
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0); //Unbind the pbo
If I am wrong in any assumptions I have made, please correct me. I am planning perhaps to use this system to tell which gui element is being clicked by rendering each of them to an fbo with a unique color and testing which pixel color was clicked on. Thanks in advance for anyone who can help!
At long last I have finally found the issue!
Firstly, using Byte.toUnsignedInt(byte), you can turn the color that the pbo gives you into your traditional 0-255 range rgb numbers.
Secondly, this being the primary issue, when OpenGL asks for pixel coordinates to fill a pbo, it is relative to bottom right. My issue was that I was using GLFW which gives coordinates relative to top right, meaning color picking in the vertical middle of the screen was accurate, but that it was getting the inverse part of the screen I was looking for when color picking elsewhere. To fix this, simply subtract the mouse click's y coordinate from the window height.
Thanks for the help and ideas!
There are a couple of possibilities, but I don't have my openGL system set up to test - but you can try these anyhow. Also I don't know Java too well ( C,C++ etc is my domain)
EDIT
1) You have asked for GL_UNSIGNED_BYTE data from glReadPixels(), but you are printing out in signed format. GL_UNSIGNED_BYTE has values 0-256, so negative values are not possible! Try to format you printout for UNSIGNED_BYTE and see where that leads. (from your code I can see this is now fixed).
2) As derhass pointed out in his comments, you should not be using the ARB (architecture Review Board) extension versions of OpenGL buffer functions since these are part of OpenGL core for quite a long time now. See https://www.khronos.org/opengl/wiki/History_of_OpenGL for version history. From this I can see glBindBufferARB (for example) was deprecated in 2003. It may or not impact your particular problem, but replace glXXXXXARB() with glXXXXX() thorughout, and make sure your OpenGL libraries are recent (v4 or later).
3) Also credit derhass, and reading your GitHub code, your getMousePosition() via glfwGetCursorPos returns screen coordinates (0,0 is top left of your window) so you need to convert to viewport coordinates (0,0 is bottom left) to read the framebuffer. Your code at GitHub seems not to be making the conversion.
4) Also credit derhass, you dont' need to use PBO at all for basic color picking. glReadPixels() default target is the framebuffer, so you can safely dispense with the VBO and get color, depth and stencil data directly from the framebuffer. (you need to enable the depth and stencil buffers).
5) If you are selecting on a 3D scene, you will also need to convert (unproject) the viewport coordinates and depth back to worldcoordinates to be able to identify which object you have clicked on. See https://en.wikibooks.org/wiki/OpenGL_Programming/Object_selection for some ideas on selection.
I hope all this helps a bit, although it feels a like learning experience for both of us.

Java opencv inRange thresholding function makes my image into three different images?

I am using java opencv and this is the line that I am executing.
Imgproc.cvtColor(originalImage, hsvImage, Imgproc.COLOR_BGR2HSV);
Core.inRange(hsvImage, low, high, thresholdImage);
low and high are some Scalar values(of size 3 each). So my original image as you can see is of 3 channels, but my thresholdImage has only one channel, why? As a result of this, when I try to display thresholdImage, I get three small images in my JFrame. How to fix this?
It turns out that Core.inRange changes the second argument, which is a Mat, to a single channel image. So in order to get 3 channels, I needed to use Imgproc.cvtColor function to re-convert it back to 3 channels.

NDK - process RGB value without Alpha from an ARGB_8888 bitmap

I have a processing algo which performs well if I process each color channel seperately. but when I tried to process the whole pixel value, things missed up. the results are not good. now I want to isolate the 3 color channel from the pixel value( exclude alpha) then work on the new value (the 3 channels).
How can I do that in C++? knowing that I tried the RGB_565 bitmap format which is not a good solution. and knowing that I want to merge the RGB into a 24bits variable.
You can access each channel separately. The exact way depends on actual pixel format.
ANDROID_BITMAP_FORMAT_RGBA_8888: each pixel is 4-byte long, layout pattern is RGBARGBA..., i.e. the 1-st pixel byte is red component, the 2-d is green, the 3-d is blue and the 4-th is alpha component.
ANDROID_BITMAP_FORMAT_RGB_565: each pixel is 2-byte long, stored in native endianness, so color components may be extracted in next way:
red = (u16_pix >> 11) & 0x1f;
green = (u16_pix >> 5) & 0x3f;
blue = (u16_pix >> 0) & 0x1f;
ANDROID_BITMAP_FORMAT_RGBA_4444:
is deprecated because of poor quality, you shouldn't even think about this one
ANDROID_BITMAP_FORMAT_A_8:
is 1 byte per pixel and designed for alpha-only or grayscale images. It is probably not what you are looking for.
Note that Android has no 24bpp format, and you must choose 32bpp or 16bpp one. About your algo: there are two alternatives - code may access individual components right inside packed pixel value, or you may deinterleave packed pixels into few planes, i.e. arrays, each of them will hold only one channel. Then after processing you may interleave them again to one of the supported formats or transform to some other format you are interested in.

How to decide which BufferedImage image type to use?

Java BufferedImage class has a long list of class variables known as the image type which can be used as an argument for the BufferedImage constructor.
However, Java docs did a minimal explanation what these image types are used for and how would it affect the BufferedImage to be created.
My question is:
How would an image type affect the BufferedImage to be created? Does it control the number of bits used to store various colors (Red,Green,Blue) and its transparency?
Which image type should we use if we just want to create
an opaque image
a transparent image
a translucent image
I read the description in the Java Doc many times, but just couldn't figure out how should we use it. For example, this one:
TYPE_INT_BGR
Represents an image with 8-bit RGB color components, corresponding to a Windows- or Solaris- style BGR color model, with the colors Blue, Green, and Red packed into integer pixels. There is no alpha. The image has a DirectColorModel. When data with non-opaque alpha is stored in an image of this type, the color data must be adjusted to a non-premultiplied form and the alpha discarded, as described in the AlphaComposite documentation.
Unless you have specific requirements (for example saving memory or saving computations or a specific native pixel format) just go with the default TYPE_INT_ARGB which has 8 bits per channel, 3 channels + alpha.
Skipping the alpha channel when working with 8 bits per channel won't affect the total memory occupied by the image since every pixel will be packed in an int in any case so 8 bits will be discarded.
Basically you have:
TYPE_INT_ARGB, 4 bytes per pixel with alpha channel
TYPE_INT_ARGB_PRE, 4 bytes per pixel, same as before but colors are already multiplied by the alpha of the pixel to save computations
TYPE_INT_RGB, 4 bytes per pixel without alpha channel
TYPE_USHORT_555_RGB and TYPE_USHORT_565_RGB, 2 bytes per pixel, much less colors, don't need to use it unless you have memory constraints
Then there are all the same kind of formats with swapped channels (eg. BGR instead that RGB). You should choose the one native of your platform so that less conversion should be done.

what values of an image should I use to produce a haar wavelet?

I currently have a Java program that will get the rgb values for each of the pixels in an image. I also have a method to calculate a Haar wavelet on a 2d matrix of values. However I don't know which values I should give to my method that calculates the Haar wavelet. Should I average each pixels rgb value and computer a haar wavelet on that? or maybe just use 1 of r, g,b.
I am trying to create a unique fingerprint for an image. I read elsewhere that this was a good method as I can take the dot product of 2 wavelets to see how similar the images are to each other.
Please let me know of what values I should be computing a Haar wavelet on.
Thanks
Jess
You should regard the R/G/B components as different images: Create one matrix for R, G and B each, then apply the wavelet to parts of those independently.
You then reconstruct the R/G/B-images from the 3 wavelet-compressed channels and finally combine those to a 3-channel bitmap.
Since eznme didn't answer your question (You want fingerprints, he explains compression and reconstruction), here's a method you'll often come across:
You separate color and brightness information (chrominance and luma), and weigh them differently. Sometimes you'll even throw away the chrominance and just use the luma part. This reduces the size of your fingerprint significantly (~factor three) and takes into account how we perceive an image - mainly by local brightness, not by absolute color. As a bonus you gain some robustness concerning color manipulation of the image.
The separation can be done in different ways, e.g. transforming your RGB image to YUV or YIQ color space. If you only want to keep the luma component, these two color spaces are equivalent. However, they encode the chrominance differently.
Here's the linear transformation for the luma Y from RGB:
Y = 0.299*R + 0.587*G + 0.114*B
When you take a look at the mathematics, you notice that we're doing nothing else than creating a grayscale image – taking into account that we perceive green brighter than red and red brighther than blue when they all are numerically equal.
Incase you want to keep a bit of chrominance information, in order to keep your fingerprint as concise as possible, you could reduce the resolution of the two U,V components (each actually 8 bit). So you could join them both into one 8 bit value by reducing their information to 4 bit and combining them with the shift operator (don't know how that works in java). The chrominance should weigh less in comparison to the luma, in the final fingerprint-distance calculation (the dot product you mentioned).

Categories