I have an image which is not a square (m x n dimension). Also its dimensions are not to the base 2 (i.e m not = 2^k & n not = 2^k). I have dealt with this by placing the image in a larger square (the next power of two) using the following:
int width = (int)Math.ceil(Math.pow(2, Math.log(img.width)/Math.log(2)));
int height = (int)Math.ceil(Math.pow(2, Math.log(img.height)/Math.log(2)));
Depending on which yields the biggest dimension, I set the square to be drawn at the max dimension, that is:
if (img.width > img.height) {
// draw width * width square
}
if (img.height > img.width) {
// draw height * height square
}
Issue:
The quadtree now looks completely different as it is storing all the non-image nodes in the tree. This obviously affects the supposed image data (i.e. min/max depths) and the entire tree shape itself. My question is, am I doing this in an efficient way and if so, how do I not store the data that doesn't belong to the image? If it isn't the best way to draw a non-square image could someone point me in the right direction? All articles on google seem to be far too in depth for my purposes.
The nice thing about quadtrees is they will store large chunks of identical data. Your extra blank image data should only be adding a little to your overall storage size. I suggest, you add an extra bit of information with your data structure that stores the actual original dimensions of the image. When deserializing your quadtree, you can "cut" off the extra part based on the actual dimensions to produce your original.
Perhaps instead of having your tree terminate in (notional) individual pixels, it could store small blocks of p pixels by o pixels, for some p x o which would make the number of blocks per side a power of two. That would make your tree behave nicely, at the expense of introducing another concept into the structure.
Related
I have a set of objects (let's call it points) that contain the x- y- and z- components of their positions within some definite space. I would like to model the interactions between the objects in points, however, I cannot do so unless I can quickly find the objects in the set that are less than a certain distance away from one of the objects in this set.
This undoubtedly sounds a bit unclear, so let me put it another way: if the first point in points has coordinates <x, y, z>, I would like to figure out which of the objects in points has a distance that is less than [some arbitrary value] from the first point.
I was considering an implementation of an R-Tree to do this in Java, yet I feel as though this is a common-enough problem that a simpler solution exists. If there is not one, I would appreciate a simple explanation of the method by which one queries an R-Tree in order to find objects that are within some distance x from an object in the tree, where x is already known.
Edit: note that the position values of these objects will be changing
The R*-tree is a pretty good data structure for this, in particular when points are changing. It is designed for changes, actually.
The k-d-tree is simpler, but it doesn't support changes very well. It is designed for a one-time bulk construction.
However, as your data is only three dimensional: if your data is small enough to fit into memory, and the maximum and minimum values of x,y,z are known, an octree or a simple grid may be the tradeoff of simplicity and performance you need.
In particular if you fix your query radius beforehand, a grid-file is hard to beat. R*-trees get attractive when you need to support multiple radiuses, window queries, nearest-neighbor queries and all this.
EDIT : Square = Cube (however imagining it in 2D space would be maybe better, then you can convert it into 3D easily)
I was thinking and I think I solved it. However this is just "my" solution, I have no reference for it.
You create class "Square", which has position, width and list of points in that object.
All squares will be stored in array or hashmap based on their position, so they can be accessed quickly, if you know position you seeks.
All squares will be distributed regularly, so - from the point of view of "point instance" - you dont have to know all the existing squares to figure out in constant time in which one you belong. (example : I know there are squares with width of 40 and they are distributed by distance of 20. I am in position 10001, so I know I belong into squares in position 9980 and 10000)
Squares will be crossed by each other, therefore one point can be in more squares.
When you do something, for each point, you only check points, which are stored in squares that point belongs to. Of course - squares have to be large enough and crossed enough to achieve your goal.
When points moving, they are responsible for registering and unregistering into the squares.
1D EXAMPLE :
Classes : Line segment and Point
Attrributes:
Line segment : int position, List<Points> points
Point : int position, List<LineSegment> lineSegments
I want to interact only with points in distance of 20.
So I create instances of Line segments with width 40 and I put them one by one in distance of 20.
So they will be at positions 0, 20, 40, 60 ....
The frist one will cover area 0-40, second 20-60 etc.
I put them into the array and with known position, I can access them quickly : arrayOfLineSegments[position/20]
When I create point, I add him to the line segments it belongs to.
When I update, each point only interacts with points in lineSegments.
When I move point, it register and unregister lineSegments it belongs to.
You can use a for loop to check through the the array of object.
use the following formula: d = sqrt[(x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2]
x1,y1,z1 being the first point in Points and the x2,y2,z2 being the points of the object you are checking. This will check your known point vs all other points. If the distance (d) is less than your desired distance x then do whatever you want you program to do.
I'm trying to figure out a geo-hashing method for images. It is hard because the space of possible images is of much higher dimensionality than lat/lng. (geo-hashing converts a location to a string where the string progressively refines the location)
So, what I need is something that:
INPUT: A list of JPG or PNG images on disk
OUTPUT: For each image a string WHERE the longer the string prefix in common between any two images, the higher chance that the two images are the same.
It doesn't need to be perfect, and it doesn't need to handle extreme cases, like cropped images or heavily adjusted images. It is intended for multiple copies of the same image at different resolutions and compression levels.
I can't use:
File or image-data hashing, because even a teeny change between two images makes a completely different hash and you don't get any proximity
Image subtraction, because it won't be a N-to-N comparison.
I've read in other answers to try wavelet compression or a laplacian/gaussian pyramid, but I'm not sure how to implement in Java or Python. However, I have made progress!
Resize to 32x32 using http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html to not discard data. Ok that everything gets turned into a square.
Create a pyramid of successively smaller thumbnails all the way down to 2x2.
In the 2x2, encode up a string of "is the next pixel brighter than the current? If so, 1, else 0" (This throws away all hue and saturation, I may want to use hue somehow)
Encode successive binary numbers from the 8x8 and 32x32 pyramids
Convert the big binary number to some higher radix representation, like Base62.
This seems to work well! Minor differences from compression or color balancing aren't enough to change a "is the left side of this area brighter than the right side". However, I think I'm re-inventing the wheel, some sort of progressive encoding might be better? SIFT and other feature-detection is overkill, I don't need to be able to handle cropping or rotation.
How about this. The hash string is made up of groups of three characters, representing red green and blue:
{R0, G0, B0}, {R1, G1, B1}, {R2, G2, B2}, ...
For each group, the image is resized to a 2^N by 2^N square. Then, the value is the sum (mod, say, 255, or whatever your encoding is) of the differences in intensity of each of the colours over some walk through the pixels.
So as a small example, to compute e.g group 1 (2x2 image) one might use the following code (I have only bothered with the red pixel)
int rSum = 0;
int rLast = 0;
for (int i=0; i<2; i++) {
for (int j=0; j<2; j++) {
rSum += Math.abs(image[i][j].r - rLast);
rLast = image[i][j].r;
}
}
rSum %= 255;
I believe this has the property that similar images should be close to each other, both for each character in the hash and in terms of successive characters in the hash.
Although for higher values of N the chance of a collision gets higher (many images will have the the same sum-of-difference values for R G and B intensities across them), each successive iteration should reveal new information about the image that was not tested with the previous iteration.
Could be fairly computationally expensive, but you have the advantage (which I infer from your question you might desire) that you can end the computation of the hash as soon as a negative is detected within a certain threshold.
Just an idea, let me know if I wasn't clear!
What you're describing seems to me to be an example of Locally Sensitive Hashing applied to the image similarity problem.
I'm not sure that the common prefix property is desirable for a good hash function. I would expect a good hash function to have two properties:
1) Good localization - for images I1 and I2 ,norm(Hash(I1)-Hash(I2)) should represent the visually percepted simiarity of I1 and I2.
2) Good compression - The high-dimension image data should be embedded in the low-dimension space of hash functions in the most discriminative way.
Getting good results from the following:
Scale down (using good scaling that doesn't discard information) to three images:
1x7
7x1
and a 6x6 image.
Convert all to grayscale.
For each image, do the "is next pixel brighter?'1':'0' encoding, output as base62.
Those outputs become the values for three columns. Nice successively refined differencing, packed into 2 chars, 2 chars, and 6 chars. True, discards all color, but still good!
I am trying to solve a problem of compositing two images in Java. The program will take a part of the first image and past it on the second image. The goal is to make the boundary between the two images less visible. The boundary must be chosen in such a way that the difference between the two images at the boundary is small.
My Tasks:
To write a method to choose the boundary between the two images. The method will receive the overlapping parts of the input images. This must first be transformed so that the boundary always starts from the left-top corner to the right-bottom corner.
Note: The returned image should not be the joined image but gives which parts of the two images were used.
The pixels of the boundary line can be marked with a constant (SEAM). Pixels of the first image can be marked with integer 0, pixels of the second image with integer 1. After choosing the boundary line, the floodfill algorithm can be used to fill the extra pixels with 0 or 1.
Note: The image can be represented as a graph whereby each pixel is connected with its left, right, top and bottom neighbor. So using the flood fill will be like depth-first search.
The "shortest path algorithm" must be used to choose the boundary in order to make it small.
Note: I cannot use any Java data structure except Arrays (not even ArrayList) or I can use my own defined data structure.
I am new in this area and am trying to solve it. What steps must I follow to solve this problem?
My main issue is, how do I represent the images as graphs in Java code (for instance with arrays or my own data structure)?
You can apply a varying opacity level at boundary to the center of image.So the edges cannot be identified.
see http://sreejithvs999.wordpress.com/2013/06/12/transparent-image-composition-in-java-fixing-an-image-over-another-with-changing-opacity-or-alpha-of-pixels/
where one image is fixed over another with changing transparency.
Here is what can be an answer to your "Main issue" part of the question.
You have to represent the images pixels as graph and also you have a restriction to use Java array only. Well if you look at a 2 dimensional array which you will need to use represent the pixels of the image, it can be used as an graph as well just that each item in the array will only have data value (pixel color) and the attached node to the current node can be calculated using the below formula:
Current pixel : [X,Y]
Top pixel : [X,Y-1]
Bottom pixel : [X,Y+1]
Left pixel : [X-1,Y]
Right pixel : [X+1,Y]
NOTE: X and Y are index in the 2D array. Also, when incrementing/decrementing X or Y to calculate neighbor pixel you need to make sure that you dont't overflow/underflow the boundary of the image i.e decrementing should not cause the value of X/Y to be < 0 and increment should not cause the X to go beyond width of image and Y to go beyond height of image.
Refer: http://docs.oracle.com/javase/tutorial/2d/images/index.html
I'm wondering if there is a "smart" way of splitting an image based on certain features.
The images are 300x57, black and white (actually grayscale, but most colors are either black or white), it is comprised of two main features (let's call them blobs) separated by black space, each blob slightly varies in width and height, the position of the blobs also varies, the blobs NEVER overlap!
Here is what an image "looks" like:
-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------
The resulting split would be something like this:
------------ -------------
----WWW----- ----WWWWW----
---WWWWWWW-- --WWWWWW-----
-----WWWW--- ----WWW------
------------ -------------
Steps I plan to take in order to split the image:
Scan the image from one side to the other.
Determine the edges of the blobs.
Take the distance between the two inside edges.
Split the image at the middle of the inside distance.
Save the two images as separate files.
It would be nice if I normalize the image widths, so all of my images have a uniform width when they're saved.
I have no experience in image manipulation, so I don't know what's an efficient way to do this. I'm currently using a BufferedImage, getting the width/height, iterating over each pixel, etc. There is no wrong solution for my problem, but I'm looking for a more efficient one (less code + faster). I've also been looking into java.awt.Graphics...
I would appreciate if I get some ideas for more efficient ways to do this task. I want to stick with Java's built-in libraries, so is BufferedImage or Graphics2D the most efficient thing to use in this case?
EDIT:
Here is the code after reading the suggestions:
public void splitAndSaveImage( BufferedImage image ) throws IOException
{
// Process image ------------------------------------------
int height = image.getHeight();
int width = image.getWidth();
boolean edgeDetected = false;
double averageColor = 0;
int threshold = -10;
int rightEdge = 0;
int leftEdge = 0;
int middle = 0;
// Scan the image and determine the edges of the blobs.
for(int w = 0; w < width; ++w)
{
for(int h = 0; h < height; ++h)
{
averageColor += image.getRGB(w, h);
}
averageColor = Math.round(averageColor/(double)height);
if( averageColor /*!=-1*/< threshold && !edgeDetected )
{
// Detected the beginning of the right blob
edgeDetected = true;
rightEdge = w;
}else if( averageColor >= threshold && edgeDetected )
{
// Detected the end of the left blob
edgeDetected = false;
leftEdge = leftEdge==0? w:leftEdge;
}
averageColor = 0;
}
// Split the image at the middle of the inside distance.
middle = (leftEdge + rightEdge)/2;
// Crop the image
BufferedImage leftImage = image.getSubimage(0, 0, middle, height);
BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height);
// Save the image
// Save to file -------------------------------------------
ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg"));
ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg"));
}
A simple way to do this is to sum the pixel values in each column (going down) to create a single array (the same width as your input image) of average values. Starting in the middle of the array, search for the minimum value. This will be the column where you can split the image.
This column probably won't be the center of the gap between your blobs. You can do another outward search from this column, going left first to find all similar columns, and then going right.
-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------
col avg:
---wwWWwww-----wWWWWww---
Depending on how blank the space is (pixel value wise) between the two blobs, you can set your threshold value pretty low. If there is some noise, it will have to be a little higher.
Finding the right threshold value can be a chore, unless you can determine it algorithmically.
I'm not aware of an edge detection algorithm that doesn't require iterating through the pixels, so your present approach may be optimal. Depending on other factors, you may be able to leverage ImageJ, which has an extensive collection of analytical plugins.
Addendum: Given a preference for avoiding external dependencies, BufferedImage is a good choice. Once you identify the edges, the getSubimage() method is convenient. You may be able to use one of the Raster getPixels() methods effectively in the convolution. ImageIO can write the results.
Does the gap between blobs matter? If you don't need to balance the white space, less work would be needed to just find a vertical white line between blobs. Check if the center vertical line has only white pixels. If the middle line has a black pixel, scan left and right for the first line that has only white pixels. To check for situations where both blobs are to one side of center, scan a horizontal line for black-white-black intervals. If the selected vertical line is within a white interval surrounded by black intervals, you'll know there's at least one blob on each side of the image split.
Failing these checks would require scanning additional lines, but for all well formed images, where the blobs are centered in the right and left halves of the image, this method will take only two line scans. This method may take longer for other images, or even break, for edge case images. This would break for this example:
-------------------------
----WWW----WWWWWWWWWW----
---WWWWWWW----WWWWWW-----
-----WWWWWWWW---WWW------
-------------------------
But the question seems to indicate this situation is impossible. If the reason behind this image splitting requires processing every image, you'll need a fall back method. You wouldn't need a fall back method if the edge cases can be rejected. Once the scanning finds that the image falls outside of acceptable ranges, you can stop checking the image. For example, if a vertical all white line can't be found in the center third of the image, you may be able to reject the image. Or you can just use this method as an optimization, running this check on just two lines to find and split the well formed images, then passing the poorly formed images to a more thorough algorithm.
I don't think there is any reason to do anything other than scanning each line and stop when you have gotten a white->black->white transition (no need to scan the entire line!).
If you can make any guess about the position of the blobs you might be able to refine it a little by picking a starting point in the middle of the image and then searching left and right from there.
But I seriously doubt it would be worth the effort.
There is also no need to first run an edge detection algorithm on the image. Just scan the lines!
EDIT: Mr. Berna pointed out that this will not work with concave objects.
I would like to resize a Java BufferedImage, making it smaller vertically but without using any type of averaging, so that if a pixel-row is "blank" (white) in the source image, there will be a white pixel-row in the corresponding position of the destination image: the "min" operation. The default algorithms (specified in getScaledInstance) do not allow me a fine-grained enough control. I would like to implement the following logic:
for each pixel row in the w-pixels wide destination image, d = pixel[w]
find the corresponding j pixel rows of the source image, s[][] = pixel[j][w]
write the new line of pixels, so that d[i] = min(s[j][i]) over all j, i
I have been reading on RescaleOp, but have not figured out how to implement this functionality -- it is admittedly a weird type of scaling. Can anyone provide me pointers on how to do this? In the worse case, I figure I can just reserve the destination ImageBuffer and copy the pixels following the pseudocode, but I was wondering if there is better way.
The RescaleOp methods include a parameter called RenderingHints. There is a hint called KEY_INTERPOLATION that decides the color to use when scaling an image.
If you use the value VALUE_INTERPOLATION_NEAREST_NEIGHBOR for the KEY_INTERPOLATION, Java will use the original colors, rather than using some type of algorithm to recalculate the new colors.
So, instead of white lines turning to gray or some mix of color, you'll get either white lines, or you won't get any lines at all. It all depends on the scaling factor, and if it's an even or odd row. For example, if you are scaling by half, then each 1 pixel horizontal line has at least a 50% change of appearing in the new image. However, if the white lines were two pixels in height, you'd have a 100% chance of the white line appearing.
This is probably the closest you're going to get besides writing your own scaling method. Unfortunately, I don't see any other hints that might help further.
To implement your own scaling method, you could create a new class that implements the BufferedImageOp interface, and implement the filter() method. Use getRGB() and setRGB() on the BufferedImage object to get the pixels from the original image and set the pixels on the new image.