java glReadpixels to OpenCV mat - java

I use lwjgl to render Images in OpenGL, now i want to store the content of the Framebuffer as RGB in an OpenCV Matrix. To make shure everything runs fine, im showing the captured image on Panel of a jFrame.
But heres the problem: While showing stored jpegs everything looks fine but if im trying to show the captured Framebuffer i only see stripes!
Here is the code for a screenshot:
public Mat takeMatScreenshot()
{
int width = m_iResolutionX;
int height = m_iResolutionY;
int pixelCount = width * height;
byte[] pixelValues = new byte[ pixelCount * 3 ];
ByteBuffer pixelBuffer = BufferUtils.createByteBuffer( width * height * 3 );
glBindFramebuffer( GL_FRAMEBUFFER, m_iFramebuffer );
glReadPixels( 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixelBuffer );
for( int i = 0; i < pixelCount; i++ )
{
int line = height - 1 - (i / width); // flipping the image upside down
int column = i % width;
int bufferIndex = ( line * width + column ) * 3;
pixelValues[bufferIndex + 0 ] = (byte)(pixelBuffer.get(bufferIndex + 0) & 0xFF) ;
pixelValues[bufferIndex + 1 ] = (byte)(pixelBuffer.get(bufferIndex + 1) & 0xFF);
pixelValues[bufferIndex + 2 ] = (byte)(pixelBuffer.get(bufferIndex + 2) & 0xFF);
}
Mat image = new Mat(width, height, CvType.CV_8UC3);
image.put(0, 0, pixelValues);
new ImageFrame(image);
return image;
}
And here the code for displaying a Mat:
public static Image toBufferedImage(Mat m)
{
int type = BufferedImage.TYPE_BYTE_GRAY;
if ( m.channels() == 3 )
type = BufferedImage.TYPE_3BYTE_BGR;
if( m.channels() == 4 )
type = BufferedImage.TYPE_4BYTE_ABGR;
int bufferSize = m.channels()*m.cols()*m.rows();
byte [] b = new byte[bufferSize];
m.get( 0, 0, b ); // get all the pixels
BufferedImage image = new BufferedImage( m.cols(), m.rows(), type );
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
It would be great if anyoune could help me!
Cheers!

Oh no! Facepalm!
The constructor of a OpenCV Mat Object is: Mat(rows, cols)!
So the right solution is:
Mat image = new Mat(height, width, CvType.CV_8UC3);
image.put(0, 0, pixelValues);

Related

How do I convert byte data into an image format that's usable within Java?

I'm currently making a Java application to take an image from a fingerprint scanner (ZK4500 model) and display it on the screen. The SDK code is pretty straight forward and I have everything working from the user's perspective. However, the only method the SDK has for drawing the image to the screen is by taking the buffered image data and writing it to a file. The file is then read into an icon data type and displayed in a JLabel.
The problem I'd like to solve is that the image buffer data is constantly written to the the hard drive and then read from the hard drive just to see what the finger print image looks like. I'd like to translate the image buffer data already in memory to be drawn to the screen... preferably in a JLabel object, but it can be in a different object if need be.
The following prepares the image data to be read from the scanner and then displayed in a JLabel...
private long device = 0;
private byte[] imageData = null; // image buffer data
private int imageWidth = 0;
private int imageHeight = 0;
private byte[] parameter = new byte[4];
private int[] size = new int[1];
device = FingerprintSensorEx.OpenDevice(0);
FingerprintSensorEx.GetParameters(device, 1, parameter, size);
imageWidth = byteArrayToInt(parameter); // (!) see next code snippet below
FingerprintSensorEx.GetParameters(device, 2, parameter, size);
imageHeight = byteArrayToInt(parameter); // (!) see next code snippet below
imageData = new byte[imageWidth * imageHeight]; // data size (284 x 369)
FingerprintSensorEx.AcquireFingerprintImage(device, imageData); // loads image buffer data
writeImageFile(imageData, imageWidth, imageHeight); // (!) see next code snippet below
imageDisplay.setIcon(new ImageIcon(ImageIO.read(new File("fingerprint.bmp")))); // jlabel object
The following is how the SDK writes the image data to a file...
private void writeImageFile(byte[] imageBuf, int nWidth, int nHeight) throws IOException {
java.io.FileOutputStream fos = new java.io.FileOutputStream("fingerprint.bmp");
java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);
int w = (((nWidth + 3) / 4) * 4);
int bfType = 0x424d;
int bfSize = 54 + 1024 + w * nHeight;
int bfReserved1 = 0;
int bfReserved2 = 0;
int bfOffBits = 54 + 1024;
dos.writeShort(bfType);
dos.write(changeByte(bfSize), 0, 4);
dos.write(changeByte(bfReserved1), 0, 2);
dos.write(changeByte(bfReserved2), 0, 2);
dos.write(changeByte(bfOffBits), 0, 4);
int biSize = 40;
int biPlanes = 1;
int biBitcount = 8;
int biCompression = 0;
int biSizeImage = w * nHeight;
int biXPelsPerMeter = 0;
int biYPelsPerMeter = 0;
int biClrUsed = 0;
int biClrImportant = 0;
dos.write(changeByte(biSize), 0, 4);
dos.write(changeByte(nWidth), 0, 4);
dos.write(changeByte(nHeight), 0, 4);
dos.write(changeByte(biPlanes), 0, 2);
dos.write(changeByte(biBitcount), 0, 2);
dos.write(changeByte(biCompression), 0, 4);
dos.write(changeByte(biSizeImage), 0, 4);
dos.write(changeByte(biXPelsPerMeter), 0, 4);
dos.write(changeByte(biYPelsPerMeter), 0, 4);
dos.write(changeByte(biClrUsed), 0, 4);
dos.write(changeByte(biClrImportant), 0, 4);
for (int i = 0; i < 256; i++) {
dos.writeByte(i);
dos.writeByte(i);
dos.writeByte(i);
dos.writeByte(0);
}
byte[] filter = null;
if (w > nWidth) {
filter = new byte[w - nWidth];
}
for (int i = 0; i < nHeight; i++) {
dos.write(imageBuf, (nHeight - 1 - i) * nWidth, nWidth);
if (w > nWidth)
dos.write(filter, 0, w - nWidth);
}
dos.flush();
dos.close();
fos.close();
}
private int byteArrayToInt(byte[] bytes) {
int number = bytes[0] & 0xFF;
number |= ((bytes[1] << 8) & 0xFF00);
number |= ((bytes[2] << 16) & 0xFF0000);
number |= ((bytes[3] << 24) & 0xFF000000);
return number;
}
private byte[] intToByteArray(final int number) {
byte[] abyte = new byte[4];
abyte[0] = (byte) (0xff & number);
abyte[1] = (byte) ((0xff00 & number) >> 8);
abyte[2] = (byte) ((0xff0000 & number) >> 16);
abyte[3] = (byte) ((0xff000000 & number) >> 24);
return abyte;
}
private byte[] changeByte(int data) {
return intToByteArray(data);
}
I included how the image data is written to the file output stream in case there is some clue as to what the real format of the scanner's image buffer data is. GIMP tells me that the written file is an 8-bit grayscale gamma integer BMP.
I know practically nothing about Java so I hope someone can point me in the right direction from a beginner's perspective. I read that a BufferedImage is the best way to work with images in Java, but I just couldn't connect the dots with the byte data from the scanner. I tried things along the line of...
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageData));
imageDisplay.setIcon(new ImageIcon(img)); // jlabel object
...but it returned an error because the image was "null". I think the image data needs to be in an array format first? Maybe the code in how the SDK writes the BMP file helps solve that, but I'm just grasping at straws here.
The writeImageFile does seem correct to me, and writes a valid BMP file that ImageIO should handle fine. However, writing the data to disk, just to read it back in, is a waste of time (and disk storage)... Instead, I would just create a BufferedImage directly from the image data.
I don't have your SDK or device, so I'm assuming the image dimensions and arrays are correctly filled (I'm just filling it with a gradient in the example):
// Dimensions from your sample code
int imageWidth = 284;
int imageHeight = 369;
byte[] imageData = new byte[imageWidth * imageHeight];
simulateCapture(imageData, imageWidth, imageHeight);
// The important parts:
// 1: Creating a new image to hold 8 bit gray data
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_BYTE_GRAY);
// 2: Setting the image data from your array to the image
image.getRaster().setDataElements(0, 0, imageWidth, imageHeight, imageData);
// And just to prove that it works
System.out.println("image = " + image);
JOptionPane.showMessageDialog(null, new ImageIcon(image), "image", JOptionPane.INFORMATION_MESSAGE);
public void simluateCapture(byte[] imageData, int imageWidth, int imageHeight) {
// Filling the image data with a gradient from black upper-left to white lower-right
for (int y = 0; y < imageHeight; y++) {
for (int x = 0; x < imageWidth; x++) {
imageData[imageWidth * y + x] = (byte) (255 * y * x / (imageHeight * imageWidth));
}
}
}
Output:
image = BufferedImage#4923ab24: type = 10 ColorModel: #pixelBits = 8 numComponents = 1 color space = java.awt.color.ICC_ColorSpace#44c8afef transparency = 1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 284 height = 369 #numDataElements 1 dataOff[0] = 0
Screenshot:

Efficiently extracting RGBA buffer from BufferedImage

I've been trying to load in bufferedImages in java as IntBuffers. However, one problem I've come across is getting the pixel data from an image with semi or complete transparency. Java only seems to allow you to get the RGB value, which in my case is a problem because any pixels that should be transparent are rendered completely opaque. After about a few hours of searching I came across this way of getting the RGBA values...
Color color = new Color(image.getRGB(x, y), true);
Although it does work, it can't possibly be the best way of doing this. Does anyone know of a more efficient way to complete the same task, one that does not require an instance of a color object for EVERY pixel. You can see how this would be bad if you're trying to load in a fairly large image. Here is my code just in case you need a reference...
public static IntBuffer getImageBuffer(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
for (int i = 0; i < pixels.length; i++) {
Color color = new Color(image.getRGB(i % width, i / width), true);
int a = color.getAlpha();
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
pixels[i] = a << 24 | b << 16 | g << 8 | r;
}
return BufferUtils.toIntBuffer(pixels);
}
public static IntBuffer toIntBuffer(int[] elements) {
IntBuffer buffer = ByteBuffer.allocateDirect(elements.length << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(elements).flip();
return buffer;
}
*Edit: The bufferedImage passed into the parameter is loaded from the disk
Here's some old code I have that converts images to OpenGL for LWJGL. Since the byte order has to be swapped, it isn't useful (I think) to load the image as for example integers.
public static ByteBuffer decodePng( BufferedImage image )
throws IOException
{
int width = image.getWidth();
int height = image.getHeight();
// Load texture contents into a byte buffer
ByteBuffer buf = ByteBuffer.allocateDirect( 4 * width * height );
// decode image
// ARGB format to -> RGBA
for( int h = 0; h < height; h++ )
for( int w = 0; w < width; w++ ) {
int argb = image.getRGB( w, h );
buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) );
buf.put( (byte) ( 0xFF & ( argb ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 24 ) ) );
}
buf.flip();
return buf;
}
Example usage:
BufferedImage image = ImageIO.read( getClass().getResourceAsStream(heightMapFile) );
int height = image.getHeight();
int width = image.getWidth();
ByteBuffer buf = TextureUtils.decodePng(image);
If interested, I did a jvm port of gli that deals with these stuff so that you don't have to worry about.
An example of texture loading:
public static int createTexture(String filename) {
Texture texture = gli.load(filename);
if (texture.empty())
return 0;
gli_.gli.gl.setProfile(gl.Profile.GL33);
gl.Format format = gli_.gli.gl.translate(texture.getFormat(), texture.getSwizzles());
gl.Target target = gli_.gli.gl.translate(texture.getTarget());
assert (texture.getFormat().isCompressed() && target == gl.Target._2D);
IntBuffer textureName = intBufferBig(1);
glGenTextures(textureName);
glBindTexture(target.getI(), textureName.get(0));
glTexParameteri(target.getI(), GL12.GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target.getI(), GL12.GL_TEXTURE_MAX_LEVEL, texture.levels() - 1);
IntBuffer swizzles = intBufferBig(4);
texture.getSwizzles().to(swizzles);
glTexParameteriv(target.getI(), GL33.GL_TEXTURE_SWIZZLE_RGBA, swizzles);
Vec3i extent = texture.extent(0);
glTexStorage2D(target.getI(), texture.levels(), format.getInternal().getI(), extent.x, extent.y);
for (int level = 0; level < texture.levels(); level++) {
extent = texture.extent(level);
glCompressedTexSubImage2D(
target.getI(), level, 0, 0, extent.x, extent.y,
format.getInternal().getI(), texture.data(0, 0, level));
}
return textureName.get(0);
}

How can I create identicons using Java or Android?

I've seen many questions about this, but all of them are C#. None of them are Java, and I couldn't find a proper library for this.
What library can do this for me programmatically by giving it a string/hash? This algorithm is actually implemented on StackExchange.
You can look at this link. There is a code that you could use to generate your identicons http://www.davidhampgonsalves.com/Identicons
The code for Java is the following one:
public static BufferedImage generateIdenticons(String text, int image_width, int image_height){
int width = 5, height = 5;
byte[] hash = text.getBytes();
BufferedImage identicon = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = identicon.getRaster();
int [] background = new int [] {255,255,255, 0};
int [] foreground = new int [] {hash[0] & 255, hash[1] & 255, hash[2] & 255, 255};
for(int x=0 ; x < width ; x++) {
//Enforce horizontal symmetry
int i = x < 3 ? x : 4 - x;
for(int y=0 ; y < height; y++) {
int [] pixelColor;
//toggle pixels based on bit being on/off
if((hash[i] >> y & 1) == 1)
pixelColor = foreground;
else
pixelColor = background;
raster.setPixel(x, y, pixelColor);
}
}
BufferedImage finalImage = new BufferedImage(image_width, image_height, BufferedImage.TYPE_INT_ARGB);
//Scale image to the size you want
AffineTransform at = new AffineTransform();
at.scale(image_width / width, image_height / height);
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
finalImage = op.filter(identicon, finalImage);
return finalImage;
}
I solved the problem.
I used Gravatar. I first got the link of the image and stored it as a String like this:
String identiconURL = "http://www.gravatar.com/avatar/" + userID + "?s=55&d=identicon&r=PG";
Then, I used Glide:
Glide.with(ProfilePictureChooserActivity.this)
.load(identiconURL)
.centerCrop()
.into(imageView);

How to set RGB pixel in a BufferedImage to display a 16-bit-depth PNG?

I am trying to read and show a PNG file.
I have no problem dealing with images with 8-bit depth.
I proceed as follow:
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Then I read the 3*8=24 bits of each pixel, save them in an array of byte data and put them in the image with:
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
result.setRGB(x, y, ((data[x * 3 + 0] & 0xff) << 16)
+ ((data[x * 3 + 1] & 0xff) << 8)
+ ((data[x * 3 + 2] & 0xff)));
The problem is now with 16-bit depth images. Of course data is bigger now and it contains 48bits, divided in 6 bytes, for each RGB triple: from the debugger data has the values I expect.
How can I set the RGB pixel? Do I have to change the BufferedImage declaration? Maybe with:
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_565_RGB);
Many thanks in advance!
P.S.: following PNG standars, the image has color type 2 (RGB without alpha).
Maybe I'll have to use http://docs.oracle.com/javase/7/docs/api/java/awt/image/ColorModel.html
#haraldK has pointed in the right direction. I'm providing some working code which is from "PNGReader" of "icafe" Java image library.
if(bitsPerPixel == 16) {
if(interlace_method==NON_INTERLACED)
spixels = generate16BitRGBPixels(compr_data, false);
else {
spixels = generate16BitRGBInterlacedPixels(compr_data, false);
}
int[] off = {0, 1, 2}; //band offset, we have 3 bands
int numOfBands = 3;
boolean hasAlpha = false;
int trans = Transparency.OPAQUE;
int[] nBits = {16, 16, 16};
if(alpha != null) { // Deal with single color transparency
off = new int[] {0, 1, 2, 3}; //band offset, we have 4 bands
numOfBands = 4;
hasAlpha = true;
trans = Transparency.TRANSLUCENT;
nBits = new int[] {16, 16, 16, 16};
}
db = new DataBufferUShort(spixels, spixels.length);
raster = Raster.createInterleavedRaster(db, width, height, width*numOfBands, numOfBands, off, null);
cm = new ComponentColorModel(colorSpace, nBits, hasAlpha, false, trans, DataBuffer.TYPE_USHORT);
}
return new BufferedImage(cm, raster, false, null);
Here is the generate16BitRGBPixels() method:
private short[] generate16BitRGBPixels(byte[] compr_data, boolean fullAlpha) throws Exception {
//
int bytesPerPixel = 0;
byte[] pixBytes;
if (fullAlpha)
bytesPerPixel = 8;
else
bytesPerPixel = 6;
bytesPerScanLine = width*bytesPerPixel;
// Now inflate the data.
pixBytes = new byte[height * bytesPerScanLine];
// Wrap an InflaterInputStream with a bufferedInputStream to speed up reading
BufferedInputStream bis = new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(compr_data)));
apply_defilter(bis, pixBytes, height, bytesPerPixel, bytesPerScanLine);
short[] spixels = null;
if(alpha != null) { // Deal with single color transparency
spixels = new short[width*height*4];
short redMask = (short)((alpha[1]&0xff)|(alpha[0]&0xff)<<8);
short greenMask = (short)((alpha[3]&0xff)|(alpha[2]&0xff)<<8);;
short blueMask = (short)((alpha[5]&0xff)|(alpha[4]&0xff)<<8);
for(int i = 0, index = 0; i < pixBytes.length; index += 4) {
short red = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
short green = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
short blue = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
spixels[index] = red;
spixels[index + 1] = green;
spixels[index + 2] = blue;
if(spixels[index] == redMask && spixels[index + 1] == greenMask && spixels[index + 2] == blueMask) {
spixels[index + 3] = (short)0x0000;
} else {
spixels[index + 3] = (short)0xffff;
}
}
} else
spixels = ArrayUtils.toShortArray(pixBytes, true);
return spixels;
}
and the ArrayUtils.toShortArray() method:
public static short[] toShortArray(byte[] data, int offset, int len, boolean bigEndian) {
ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, len);
if (bigEndian) {
byteBuffer.order(ByteOrder.BIG_ENDIAN);
} else {
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
}
ShortBuffer shortBuf = byteBuffer.asShortBuffer();
short[] array = new short[shortBuf.remaining()];
shortBuf.get(array);
return array;
}
If you want to create an image with 16 bits per sample (or 48 bits per pixel), there is no BufferedImage.TYPE_... constant for that. TYPE_USHORT_565_RGB creates an image with 16 bits per pixel, with samples of 5 (red), 6 (green) and 5 (blue) bits respectively. I think these USHORT RGB values are leftovers from a time when some computes actually had the option of a 16 bit display (aka "Thousands of colors").
What you need to do, to actually create an image with 16 bits per sample, is:
ColorModel cm;
WritableRaster raster;
BufferedImage result = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
The raster is created from a data buffer of type DataBufferUShort with either 3 banks and a BandedSampleModel with 3 bands, or use a single bank and a PixelInterleavedSampleModel with a pixelStride of 3, scanLineStride of 3 * width and bandOffsets {0, 1, 2}.
Here's a full sample, using interleaved sample model:
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB)
ColorModel cm = new ComponentColorModel(sRGB, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 3, null);
BufferedImage rgb = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
PS: With the data buffer exposed, you can access the short samples directly, to manipulate the pixels. This is much faster than using BufferedImage.getRGB(...)/setRGB(...), and will keep the original 16 bit per sample precision. BufferedImage.getRGB(...) will convert the pixel values to 32 bit pixel/8 bit per sample, and thus lose the extra precision.

DCT2 of png using jTransforms

What I'm trying to do is to compute 2D DCT of an image in Java and then save the result back to file.
Read file:
coverImage = readImg(coverPath);
private BufferedImage readImg(String path) {
BufferedImage destination = null;
try {
destination = ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
return destination;
}
Convert to float array:
cover = convertToFloatArray(coverImage);
private float[] convertToFloatArray(BufferedImage source) {
securedImage = (WritableRaster) source.getData();
float[] floatArray = new float[source.getHeight() * source.getWidth()];
floatArray = securedImage.getPixels(0, 0, source.getWidth(), source.getHeight(), floatArray);
return floatArray;
}
Run the DCT:
runDCT(cover, coverImage.getHeight(), coverImage.getWidth());
private void runDCT(float[] floatArray, int rows, int cols) {
dct = new FloatDCT_2D(rows, cols);
dct.forward(floatArray, false);
securedImage.setPixels(0, 0, cols, rows, floatArray);
}
And then save it as image:
convertDctToImage(securedImage, coverImage.getHeight(), coverImage.getWidth());
private void convertDctToImage(WritableRaster secured, int rows, int cols) {
coverImage.setData(secured);
File file = new File(securedPath);
try {
ImageIO.write(coverImage, "png", file);
} catch (IOException ex) {
Logger.getLogger(DCT2D.class.getName()).log(Level.SEVERE, null, ex);
}
}
But what I get is: http://kyle.pl/up/2012/05/29/dct_stack.png
Can anyone tell me what I'm doing wrong? Or maybe I don't understand something here?
This is a piece of code, that works for me:
//reading image
BufferedImage image = javax.imageio.ImageIO.read(new File(filename));
//width * 2, because DoubleFFT_2D needs 2x more space - for Real and Imaginary parts of complex numbers
double[][] brightness = new double[img.getHeight()][img.getWidth() * 2];
//convert colored image to grayscale (brightness of each pixel)
for ( int y = 0; y < image.getHeight(); y++ ) {
raster.getDataElements( 0, y, image.getWidth(), 1, dataElements );
for ( int x = 0; x < image.getWidth(); x++ ) {
//notice x and y swapped - it's JTransforms format of arrays
brightness[y][x] = brightnessRGB(dataElements[x]);
}
}
//do FT (not FFT, because FFT is only* for images with width and height being 2**N)
//DoubleFFT_2D writes data to the same array - to brightness
new DoubleFFT_2D(img.getHeight(), img.getWidth()).realForwardFull(brightness);
//visualising frequency domain
BufferedImage fd = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
outRaster = fd.getRaster();
for ( int y = 0; y < img.getHeight(); y++ ) {
for ( int x = 0; x < img.getWidth(); x++ ) {
//we calculate complex number vector length (sqrt(Re**2 + Im**2)). But these lengths are to big to
//fit in 0 - 255 scale of colors. So I divide it on 223. Instead of "223", you may want to choose
//another factor, wich would make you frequency domain look best
int power = (int) (Math.sqrt(Math.pow(brightness[y][2 * x], 2) + Math.pow(brightness[y][2 * x + 1], 2)) / 223);
power = power > 255 ? 255 : power;
//draw a grayscale color on image "fd"
fd.setRGB(x, y, new Color(c, c, c).getRGB());
}
}
draw(fd);
Resulting image should look like big black space in the middle and white spots in all four corners. Usually people visualise FD so, that zero frequency appears in the center of the image. So, if you need classical FD (one, that looks like star for reallife images), you need to upgrade "fd.setRGB(x, y..." a bit:
int w2 = img.getWidth() / 2;
int h2 = img.getHeight() / 2;
int newX = x + w2 >= img.getWidth() ? x - w2 : x + w2;
int newY = y + h2 >= img.getHeight() ? y - h2 : y + h2;
fd.setRGB(newX, newY, new Color(power, power, power).getRGB());
brightnessRGB and draw methods for the lazy:
public static int brightnessRGB(int rgb) {
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
return (r+g+b)/3;
}
private static void draw(BufferedImage img) {
JLabel picLabel = new JLabel(new ImageIcon(img));
JPanel jPanelMain = new JPanel();
jPanelMain.add(picLabel);
JFrame jFrame = new JFrame();
jFrame.add(jPanelMain);
jFrame.pack();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
}
I know, I'm a bit late, but I just did all that for my program. So, let it be here for those, who'll get here from googling.

Categories

Resources