Confused about setting median values of a coloured image - java

I am implementing a median filter in Java using a Bitmap image. I am using an algorithm implemented in another programming language and then converting it to Java for my implementation. The part of the algorithm that I do not understand is below:
for(int x = 0; x < w; x++)
for(int y = 0; y < h; y++)
{
int n = 0;
//set the color values in the arrays
for(int filterX = 0; filterX < filterWidth; filterX++)
for(int filterY = 0; filterY < filterHeight; filterY++)
{
int imageX = (x - filterWidth / 2 + filterX + w) % w;
int imageY = (y - filterHeight / 2 + filterY + h) % h;
red[n] = image[imageX][imageY].r;
green[n] = image[imageX][imageY].g;
blue[n] = image[imageX][imageY].b;
n++;
}
Here is the link to the Median Algorithm
I implemented the following code myself but I dont think it is correct. I would appreciate if someone can help me please.
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
int n = 0;
for(int filterX = 0; filterX < filterWidth; filterX++)
for(int filterY = 0; filterY < filterHeight; filterY++)
{
pixel = image.getPixel(x,y);
A = (pixel>>24) & 0xFF;
R = (pixel>>16) & 0xFF;
G = (pixel>>8) & 0xFF;
B = pixel & 0xFF;
RArray[n] = R;
GArray[n] = G;
BArray[n] = B;
n++;
}

I don't see where you are selecting the median of the input values. As Jim mentioned, be sure to handle the edge cases, for example...
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
int index = 0;
for(int filterX = -filterWidth/2; filterX < filterWidth/2; filterX++)
for(int filterY = -filterHeight/2;
filterY < filterHeight/2; filterY++)
{
int pixelX = x+filterX;
int pixelY = y+filterY;
//ensure we're in bounds.
if(pixelX>-1 && pixelY>-1 && pixelX<w && pixelY<h){
pixel = image.getPixel(x,y);
A = (pixel>>24) & 0xFF;
R = (pixel>>16) & 0xFF;
G = (pixel>>8) & 0xFF;
B = pixel & 0xFF;
RArray[index] = R;
GArray[index] = G;
BArray[index] = B;
++index;
}
}
//only sort the pieces of the array we've put data into,
//remember we could be on an edge of the image.
Arrays.sort(RArray,0,index);
Arrays.sort(BArray,0,index);
Arrays.sort(GArray,0,index);
int medianR = RArray[RArray.length/2];
int medianB = BArray[BArray.length/2];
int medianG = GArray[GArray.length/2];
//last step is to combine medians back into a single integer

You need to analyze N pixels and find the middle value to get the median.
You need to use the changing filterX and filterY values as offsets to get other pixels than just x and y.
getPixel(x+filterX,y+filterY)

Related

Find average of List<Point> in Java

I have a List variable 'l' which has values like this:
List<Point> l = new ArrayList<Point>();
Imgproc.convexHull(contours,hull);
for (int j = 0; j < intlist.length; j++) {
l.add(contours.toList().get(hull.toList().get(j)));
}
After this I am getting following values of l:
l = [{1,2}, {3,4}, {5,6}]
and so on. How to find the average of 1st and 2nd values in l.get(i) for all i, as an array. For example, for the above I want the following:
x = 3
y = 4
Finally I got the answer! Below code will do the job:
double sum_x = 0;
double sum_y = 0;
int j;
for (j = 0; j < hull.size().height; j++) {
l.add(contours.toList().get(hull.toList().get(j)));
sum_x += l.get(j).x;
sum_y += l.get(j).y;
}
x = sum_x / j;
y = sum_y / j;

how to cut a 3X3 array from a given grid with out indexOutOfBound exception

im stuck building a function that takes a given 2d-char array and a Point inside of it, that takes the given point coordinate and builds a new 2d-char array that surrounds the point.
for example if the original grid is:
a b c d e
z h a f c
g y z q x
r z x s a
k j h z z
the answer of point (0,0) should be:
? ? ?
? a b
? z h
the answer of point(2,2) should be:
h a f
y z q
z x s
public int numOfColors(Point p) {
char [][] neighbors = new char[3][3];
for(int i = 0; i < neighbors.length; i++){
for(int j = 0; j < neighbors.length; j++){
neighbors[i][j]='?';
}
}
int pX = p.getX(), pY = p.getY();
for(int i = pX - 1; (i < map.length) && (i < pX + 1) ; i++){ //runs on the original map and copy to neighbors
for (int j = pY - 1; (j < map.length) && (j < pY + 1); j++){
neighbors[i-pX+1][j-pY+1]=map[i][j];
}
}
for(int k = 0; k < neighbors.length; k++){ //runs on the neighbors array. if a point is an edge point.copy the given point color to the '?' cell
for(int l = 0; l < neighbors.length; l++){
if(neighbors[k][l]=='?')
neighbors[k][l]= map[pX][pY];
}
}
I've been sitting on this all day, the correct answer will be rewarded with a beer
I would like to begin from a helper method
private char getValue(int x, int y) {
if (x < 0 || x >= xSize || y < 0 || y >= ySize) {
return '?';
}
return neighbors[x][y];
}
public static void extract(char [][] arr, int row, int col){
char [][] ex = new char [3][3];
int rc = 0;
int cc = 0;
for(int i=row-1; i<row+2; i++){
for(int j=col-1; j<col+2; j++){
if(i < 0 || j < 0 || i >= arr.length || j >= arr[i].length){
ex[rc][cc] = '?';
} else {
ex[rc][cc] = arr[i][j];
}
cc++;
}
rc++;
cc = 0;
}
for(int i=0; i<3;i++){
for(int j=0; j<3; j++){
System.out.print (ex[i][j] +" ");
}
System.out.println();
}
}
Row, Col is Point(x,y).
I'm assuming the out of bounds exception is happened when using this bit of code, since you aren't checking if px - 1 is -1 and the same for py:
for(int i = px - 1; (i < map.length) && (i < px + 1) ; i++){ //runs on the original map and copy to neighbors
for (int j = py - 1; (j < map.length) && (j < py + 1); j++){
neighbors[i-pX+1][j-pY+1]=map[i][j];
}
}
You could change it to something like this:
int x1 = Math.max(p.getX() - 1, 0);
int x2 = Math.min(p.getX() + 1, map.length);
int y1 = Math.max(p.getY() - 1, 0);
int y2 = Math.min(p.getY() + 1, map[0].length);
int xCount = 0;
int yCount = 0;
and then:
for(int i = x1; i < x2; i++) { //runs on the original map and copy to neighbors
for (int j = y1; j < y2; j++) {
neighbors[xCount][yCount++]=map[i][j];
}
yCount = 0;
xCount++;
}

Indexing string for insertion into char[][][] array

I'm a little stuck on the arithmetic for this program. I have a string theString that has a length of x*y*z. x, y, and z are the dimensions of a char[][][] array (lets call it cArr).
I want to insert the characters of theString into cArr based on a specific index. Here's an example of a 5x4x3 array.
String theString = someMethod(); //returns a string of length 60
char[][][] cArr = new char[5][4][3];
for (int z = 0; z < 3; z++) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 5; x++) {
cArr[x][y][z] = theString.charAt(/*~~~*/);
}
}
}
I can figure out the arithmetic to insert characters into a char[5][4] array from a string of length 20:
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 5; x++) {
cArr[x][y] = theString.charAt((5*y)+x);
}
}
What arithmetic should I be using in the charAt() method for a 3-dimensional char array?
My best attempt has been:
char[][][] cArr = new char[5][4][3];
for (int z = 0; z < 3; z++) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 5; x++) {
cArr[x][y][z] = theString.charAt(((3^2)*z)+(4*y)+x);
}
}
}
But this makes all z-index layers of cArr the same.
The rule is simple for problems like this. You start from the innermost loop and proceed up with x + y*(length of x) + z*(length of y)*(length of x).
In this example, it would be,
cArr[x][y][z] = theString.charAt(x + y*5 + z*4*5);

Average value of bytes

I have such a problem. I want to make "average" image from the few diffirent. my idea was to load them to BufferImage sequentially, sum values in each bit, and than just divide by number of photos. The problem is that i can't divide byte[][] by number. What am i doing wrong, or what is the proper way to do this?
File[] others = getOtherImageFiles(file);
byte[][] pixels = new byte[300][];
List<byte[][]> pixelsList = new ArrayList<byte[][]>();
for (int i = 0; i < others.length; i++) {
try {
img = ImageIO.read(others[i]);
} catch (IOException e) {
}
for (int x = 0; x < img.getWidth(); x++) {
pixels[x] = new byte[img.getHeight()];
for (int y = 0; y < img.getHeight(); y++) {
pixels[x][y] = (byte) (img.getRGB(x, y));
}
}
pixelsList.add(pixels);
}
byte[][] pixelsSum = new byte[300][];
for (int i = 0; i < pixelsList.size(); i++) {
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
pixelsSum[x][y] += pixelsList.get(i)[x][y];
}
}
}
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
pixelsSum[x][y]/10;
}
}
}
i want to use them as a face comparer and the point is to create a scheme of faces.
You're close. You did the division by 10, but you never wrote the result back into the pixelsSum array, so the result is lost. You need to do:
pixelsSum[x][y] = pixelsSum[x][y] / 10;
or in shorthand:
pixelsSum[x][y] /= 10;
Another problem you will run into is that each byte in Java (or any other language) can only hold values between 0 and 255. So if you have a bytes x = 255, y = 1, x + y will turn out to be 0. When you add up 10 images, it will almost certainly go over the 255 limit. I suggest changing pixelsSum from byte[][] to int[][], and then turn it back to bytes after you do the division.
Instead of this set of loops:
for (int i = 0; i < pixelsList.size(); i++) {
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
pixelsSum[x][y] += pixelsList.get(i)[x][y];
}
}
}
you should put the pixelsList reference in the middle:
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
for (int i = 0; i < pixelsList.size(); i++) {
pixelsSum[x][y] += pixelsList.get(i)[x][y];
}
pixelsSum[x][y] /= pixelsList.size();
}
}
This should calculate the average immediately rather than looping through the pixelsSum array again. Note also the use of the /= operator which performs both division and assignment compared with the / operator which is limited to division in the context of numbers.

Having problems with a 2d terrain generator in Java

For some reason the blocks keep being rendered in the same position. Can anybody help me?
Block[][] chunk = new Block[Chunk.CHUNK_WIDTH_BLOCKS][Chunk.CHUNK_HEIGHT_BLOCKS];
float[][] positions = new float[Chunk.CHUNK_WIDTH_BLOCKS][Chunk.CHUNK_HEIGHT_BLOCKS];
float frequency = 1.0f / (float) chunk.length;
for (int x = 0; x < chunk.length - 1; x++)
{
for (int y = 0; y < chunk[x].length - 1; y++)
{
positions[x][y] = SimplexNoise.Generate((float) x * frequency, (float) y * frequency);
g.drawRect(positions[x][0], positions[0][y], Block.BLOCK_WIDTH, Block.BLOCK_HEIGHT);
}
}
for (int x = 0; x < Chunk.CHUNK_WIDTH_BLOCKS; x++)
{
for (int y = 0; y < Chunk.CHUNK_HEIGHT_BLOCKS; y++)
{
if (positions[x][y] < 0f)
chunk[x][y] = new Block();
if (positions[x][y] >= -0f)
chunk[x][y] = new Block();
}
}
You have multiple problems with your code. For instance:
for (int x = 0; x < chunk.length - 1; x++)
That should be:
for (int x = 0; x < chunk.length; x++)
Also, consider the following:
g.drawRect(positions[x][0], positions[0][y], Block.BLOCK_WIDTH, Block.BLOCK_HEIGHT);
That will not use all values in "positions[x][y]".... I think that what you will want is for the array to be 3d... for instance:
float[][][] positions = new float[Chunk.CHUNK_WIDTH_BLOCKS][Chunk.CHUNK_HEIGHT_BLOCKS][2];
That way: posistions[x][y][0] is the value for x, and positions[x][y][1] is the value for y....
g.drawRect(positions[x][y][0], positions[x][y][1], Block.BLOCK_WIDTH, Block.BLOCK_HEIGHT);
I am not sure I understand your code exactly, but it does seem to have issues.

Categories