android compare 2 images and highlight difference - java

2 Images will be provided. We need to find differences between them and highlight them.
So far I have seen this solution in JAVA but as BufferedImage is not supported in android, I am unable to proceed further. I have come close to comparing pixels of 2 Bitmaps but facing issue ahead.
I have also tried comparing pixels of two bitmap, but it highlights all the non-white colors
void findDifference(Bitmap firstImage, Bitmap secondImage)
{
if (firstImage.getHeight() != secondImage.getHeight() && firstImage.getWidth() != secondImage.getWidth())
Toast.makeText(this, "Images size are not same", Toast.LENGTH_LONG).show();
boolean isSame = true;
for (int i = 0; i < firstImage.getWidth(); i++)
{
for (int j = 0; j < firstImage.getHeight(); j++)
{
if (firstImage.getPixel(i,j) == secondImage.getPixel(i,j))
{
}
else
{
differentPixels.add(new Pixel(i,j));
secondImage.setPixel(i,j, Color.YELLOW); //for now just changing difference to yello color
isSame = false;
}
}
}
imgOutput.setImageBitmap(secondImage);
}
Thanks in advance.

With the help of digital color meter I detected there is very slight difference between colors of visually looking similar images quite similar what #taarraas also suggested. so I took a threshold value and solved it like this.
private static final int threashold = 10;
void findDifference(Bitmap firstImage, Bitmap secondImage)
{
if (firstImage.getHeight() != secondImage.getHeight() || firstImage.getWidth() != secondImage.getWidth())
Toast.makeText(this, "Images size are not same", Toast.LENGTH_LONG).show();
boolean isSame = true;
for (int i = 0; i < firstImage.getWidth(); i++)
{
for (int j = 0; j < firstImage.getHeight(); j++)
{
int pixel = firstImage.getPixel(i,j);
int redValue = Color.red(pixel);
int blueValue = Color.blue(pixel);
int greenValue = Color.green(pixel);
int pixel2 = secondImage.getPixel(i,j);
int redValue2 = Color.red(pixel2);
int blueValue2 = Color.blue(pixel2);
int greenValue2 = Color.green(pixel2);
if (Math.abs(redValue2 - redValue) + Math.abs(blueValue2 - blueValue) + Math.abs(greenValue2 - greenValue) <= threashold)
// if (firstImage.getPixel(i,j) == secondImage.getPixel(i,j))
{
}
else
{
differentPixels.add(new Pixel(i,j));
secondImage.setPixel(i,j, Color.YELLOW); //for now just changing difference to yello color
isSame = false;
}
}
}
imgOutput.setImageBitmap(secondImage);
}

Comparing the images pixel by pixel you can do it like this:
private void findDifference(Bitmap firstImage, Bitmap secondImage) {
Bitmap bmp = secondImage.copy(secondImage.getConfig(), true);
if (firstImage.getWidth() != secondImage.getWidth()
|| firstImage.getHeight() != secondImage.getHeight()) {
return;
}
for (int i = 0; i < firstImage.getWidth(); i++) {
for (int j = 0; j < firstImage.getHeight(); j++) {
if (firstImage.getPixel(i, j) != secondImage.getPixel(i, j)) {
bmp.setPixel(i, j, Color.YELLOW);
}
}
}
imgOutput.setImageBitmap(bmp);
}

Related

Scrolling text effect on 2D array

For a project I am working on I would like to be abbe to "scroll" an array like so:
Here is the code I have so far:
private boolean[][] display = this.parseTo8BitMatrix("Here");
private int scroll = 0;
public void scroll() {
this.scroll++;
}
//sets the clock's display
public void setDisplay(String s) {
this.display = this.parseTo8BitMatrix(s);
}
//determines the current frame of the clock
private boolean[][] currentFrame() {
boolean[][] currentFrame = new boolean[8][32];
int length = this.display[0].length;
if(length == 32) { //do nothing
currentFrame = this.display;
} else if(length <= 24) { //center
for(int i = 0; i < 8; i++) {
for(int j = 0; j < length; j++) {
currentFrame[i][j+((32-length)/2)] = this.display[i][j];
}
}
this.display = currentFrame; //set display to currentFrame so the display doesn't get centered each time
} else { //scroll
for(int i = 0; i < 8; i++) {
for(int j = 0; j < length; j++) {
if(this.scroll+j <= 32) {
currentFrame[i][j] = this.display[i][j+this.scroll];
} else {
//?
}
}
}
}
return currentFrame;
}
The code I have is effective up until the the array needs to "wrap around" to the other side. Where have I gone wrong?
I'm assuming that you're looking for a formula that would work for the else.
Usually Modulos are very helpful for wrapping around.
What you are looking for is basically
currentFrame[i][j]= this.display[i][(j+this.scroll)%length];
which works even when it's not wrapped around.

i need a function opencv in java return the percentage of the color in the mat , please

i need a function opencv in java return the percentage of the color in the mat , please
public boolean procentage(Mat imageOne, int porsontageDeChangemnt) {
boolean tr = false;
int width = (int) imageOne.width();
int height = (int) imageOne.height();
int maxPixel = width * height;
int cont = 0;
try {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
double[] colorPixel = imageOne.get(i, j);
if (((int) colorPixel[0] == 255)) {
cont++;
}
}
}
} catch (Exception e) {
}
int c = (int) ((cont * 100) / maxPixel);
if (c >= porsontageDeChangemnt) {
tr = true;
}
if (c > porsontageDeChangemnt) {
tr = true;
}
return tr;
}
exception in this line >> if (((int) colorPixel[0] == 255)) {
So you have not provided a full implementation but I slightly modified it to get something similar running.
If you break down your code all the way to the basic level and try something like this:
for (int j = 0; j < 300; j++) {
double[] colorPixel = null; //This what your code thinks it is doing
if (((int) colorPixel[0] == 255)) {
System.out.println(colorPixel.toString());
}
You will get the same exception on the same line you are currently. The problem is you are passing a null value to imageOne in the method procentage at some point.
If you want to get a clearer answer you will need to ask a clearer question, since the exact problem is not shown in the code you have written here.

IF Statement Checking (Not Working Properly)

randomEmpty() returns a random coordinate on the n x n grid that is empty (Method works). randomAdjacent() uses randomEmpty() to select an EMPTY coordinate on the map. Comparisons are then made to see if this coordinate has an VALID adjacent coordinate that is NON-EMPTY. The PROBLEM is that randomAdjacent does not always return the coordinates of space with an adjacent NON-EMPTY space. It will always return valid coordinates but not the latter. I can't spot the problem. Can someone help me identify the problem?
public int[] randomEmpty()
{
Random r = new Random();
int[] random = new int[2];
int row = r.nextInt(array.length);
int column = r.nextInt(array.length);
while(!(isEmpty(row,column)))
{
row = r.nextInt(array.length);
column = r.nextInt(array.length);
}
random[0] = row+1;
random[1] = column+1;
return random;
}
public int[] randomAdjacent()
{
int[] adjacentToX = new int[8];
int[] adjacentToY = new int[8];
int[] adjacentFrom = randomEmpty();
int count;
boolean isTrue = false;
boolean oneAdjacentNotEmpty = false;
while(!(oneAdjacentNotEmpty))
{
count = 0;
if(validIndex(adjacentFrom,1,-1))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,0,-1))
{
adjacentToX[count] = adjacentFrom[0];
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,-1,-1))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,-1,0))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1];
count++;
}
if(validIndex(adjacentFrom,-1,1))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,0,1))
{
adjacentToX[count] = adjacentFrom[0];
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,1,1))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,1,0))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1];
count++;
}
for(int i = 0; i < count; i++)
{
if(!(isEmpty(adjacentToX[i],adjacentToY[i])))
{
oneAdjacentNotEmpty = true;
isTrue = true;
}
}
if(isTrue)
break;
else
adjacentFrom = randomEmpty();
}
return adjacentFrom;
}
public boolean validIndex(int[] a,int i, int j)
{
try
{
Pebble aPebble = array[a[0]+i][a[1]+j];
return true;
}
catch(ArrayIndexOutOfBoundsException e)
{
return false;
}
}
public void setCell(int xPos, int yPos, Pebble aPebble)
{
array[xPos-1][yPos-1] = aPebble;
}
public Pebble getCell(int xPos, int yPos)
{
return array[xPos-1][yPos-1];
}
JUNIT Test Performed:
#Test
public void testRandomAdjacent() {
final int size = 5;
final Board board2 = new Board(size);
board2.setCell(1, 1, Pebble.O);
board2.setCell(5, 5, Pebble.O);
int[] idx = board2.randomAdjacent();
int x = idx[0];
int y = idx[1];
boolean empty = true;
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
if ((i == x && j == y) || i < 1 || j < 1 || i > size || j > size) {
continue;
}
if (board2.getCell(i, j) != Pebble.EMPTY)
empty = false;
}
}
assertFalse(empty);// NEVER gets SET TO FALSE
assertEquals(Pebble.EMPTY, board2.getCell(x, y));
}
As for the answer: I got carried away optimizing your code for readability. I'd think it's most likely
if (board2.getCell(i, j) != Pebble.EMPTY)
empty = false;
causing the problem as getCell operates in 1-based coordinates, but i, j are in 0-based.
You should think about your logic overall. The way I see it, your code might never terminate as randomEmpty() could keep returning the same field over and over again for an undetermined period of time.
I took the liberty to recode your if-if-if cascade into utility method easier to read:
public boolean hasNonEmptyNeighbor(int[] adjacentFrom) {
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
if(validIndex(adjacentFrom, i, j) //Still inside the board
&& // AND
!isEmpty(adjacentFrom[0]+i //not empty
,adjacentFrom[1]+j)) {
return true;
}
}
}
return false;
}
Given my previous comment about random() being not the best of choices if you need to cover the full board, your main check (give me an empty cell with a non-empty neighbor) could be rewritten like this:
public void find() {
List<Point> foundPoints = new ArrayList<Point>();
for(int i = 0; i < Board.height; ++i) { //Assumes you have stored your height
for(int j = 0; j < Board.width; ++j) { //and your width
if(isEmpty(i, j) && hasNonEmptyNeighbor(new int[]{i,j})) {
//Found one.
foundPoints.add(new Point(i, j));
}
}
}
//If you need to return a RANDOM empty field with non-empty neighbor
//you could randomize over length of foundPoints here and select from that list.
}

Refining custom flood fill algorithm (Java)

I have no experience with any type of flood fill algorithms at all. But I gave it my best shot. At first, I would fill one pixel wherever the user clicked with magenta, and then went through a loop which drew a pixel on top, left, bottom, and right of each magenta pixel. This would take up to 8 seconds to complete the fill with especially large areas. So I added another loop which drew straight magenta-colored lines up, down, left, and right. This halved the time. I had the computer draw more lines... up-up-left, up-left, up-left-left, down-left-left... etc. Now it's down to between 1 & 2 seconds. What else can I do to decrease the amount of time it takes to complete the fill?
for(Point p:shiftDownPoints)
{
//down
for(int y = p.y+1; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//up
for(int y = p.y-1; y>0; y--)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//right
for(int x = p.x+1; x<SCREEN_DIM.width; x++)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//left
for(int x = p.x-1; x>0; x--)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i,Color.MAGENTA.getRGB());
}
//down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i,Color.MAGENTA.getRGB());
}
//up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i,Color.MAGENTA.getRGB());
}
//up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i*2,Color.MAGENTA.getRGB());
}
//up-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y-i,Color.MAGENTA.getRGB());
}
//down-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y+i,Color.MAGENTA.getRGB());
}
//down-down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y+i,Color.MAGENTA.getRGB());
}
//up-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i*2,Color.MAGENTA.getRGB());
}
}
while(pixelsDrawn)
{
pixelsDrawn=false;
for(int x = 0; x<SCREEN_DIM.width; x++)
for(int y = 0; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(x,y)==Color.MAGENTA.getRGB())
{
if(capture.getRGB(x-1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x-1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x-1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x+1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x+1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x+1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y-1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y-1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y-1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y+1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y+1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y+1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
}
}
}
Thanks to immibis's suggestion, I got my flood-fill down to half a second. In this new code, I had the computer go along the edge of the outline and create a polygon, and then just used fillPolygon from the graphics.
for(Point p:iterablePoints)
{
int dir = 2; //0:right, 1:down, 2:left, 3:up
int xPos = p.x;
int yPos = 0;
Polygon poly = new Polygon();
for(int y = p.y; y>0; y--)
{
if(capture.getRGB(p.x,y-1)==Color.BLACK.getRGB())
{
yPos = y;
break;
}
}
Vector<Point> tempRecord = new Vector<Point>();
boolean run = true;
while(run)
{
if(dir==0&&capture.getRGB(xPos+1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==1&&capture.getRGB(xPos,yPos+1)==Color.BLACK.getRGB())dir--;
else if(dir==2&&capture.getRGB(xPos-1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==3&&capture.getRGB(xPos,yPos-1)==Color.BLACK.getRGB())dir--;
else
{
if(dir==0)xPos++;
if(dir==1)yPos++;
if(dir==2)xPos--;
if(dir==3)yPos--;
dir++;
tempRecord.add(new Point(xPos,yPos));
if(tempRecord.size()>1)if(tempRecord.get(0)==tempRecord.get(1))tempRecord.remove(tempRecord.firstElement());
else startPoint = tempRecord.get(0);
if(startPoint!=null)if(startPoint.x==xPos&&startPoint.y==yPos) run=false;
poly.addPoint(xPos,yPos);capture.setRGB(xPos,yPos,Color.MAGENTA.getRGB());
}
if(dir==4)dir=0;
if(dir==-1)dir=3;
}
Graphics cg = capture.getGraphics();
cg.setColor(Color.MAGENTA);
cg.fillPolygon(poly);
cg.dispose();
}
Discussing flood fill algorithm could take a full class session. I think you should consult This Link as it explain everything, how pixel-by-pixel get painted(efficiently) together with algorithm. Hope this helps.

How to find all connected numbers in an array?

Hey all, back again. Working on a dungeon generator and I'm actually surprising myself with the progress. Yet I still have a straggling room every now and then. I was wondering if there was a way to loop through an array and see if all the '1s' (the floor tiles) are connected, and if not, how to connect them.
Thanks!
EDIT: The array is randomly filled with rooms and corridors; here's the code:
import java.util.Random;
public class Level
{
Random random = new Random();
int[][] A = new int[100][100];
int minimum = 3;
int maximum = 7;
int xFeature = 0;
int yFeature = 0;
private void feature()
{
int i = 0;
while(i>=0)
{
xFeature = random.nextInt(100-1) + 1;
yFeature = random.nextInt(100-1) + 1;
if(A[xFeature][yFeature]==1)//||A[xFeature++][yFeature]==1||A[xFeature][yFeature--]==1||A[xFeature][yFeature++]==1)
break;
i++;
}
}
private void room()
{
int safeFall = 0;
int xCoPLUS = minimum + (int)(Math.random()*minimum);
int yCoPLUS = minimum + (int)(Math.random()*minimum);
if(yCoPLUS >= xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+2; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+1; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if(yCoPLUS < xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+1; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+2; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if((safeFall== (xCoPLUS+1) * (yCoPLUS+2)) || ((safeFall== (xCoPLUS+2) * (yCoPLUS+1))))
{
for(int across = xFeature; across < xFeature+xCoPLUS; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS; vert++)
{
A[vert][across] = 1;
}
}
}
}
private void corridor()
{
int xCoONE = xFeature;
int yCoONE = yFeature;
int xCoTWO = random.nextInt(10)+10;
int yCoTWO = random.nextInt(10)+10;
while(xCoONE > xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE--;
}
while(xCoONE < xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE++;
}
while(yCoONE > yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE--;
}
while(yCoONE < yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE++;
}
}
public Level()
{
firstroom();
for(int i = 0; i < 500; i++)
{
int x = random.nextInt(50);
feature();
if(x > 1)
room();
else
corridor();
}
troubleShoot();
}
So basically what happens when I create an object of this class is that a 100x100 array is filled with corridors and rooms determined by a random number. (well, a couple of them) But with how I have my room non-overlapping failsafe (safeFall in room()), I get stuck with a room that is one title out of reach every now and then.
The article Maze Generation Algorithm discusses several approaches to generating a maze. It includes links to Java examples.

Categories

Resources