Java Convolution (Array Out Of Index Error) - java

i am writing a program that will read the element in a convolute and the program will then multiple each element in the convolute with the kernel given. I will need to take the convolute array from other class as well as kernel.
But i am getting this Error message: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
The error will be specified in the comment section with capitalised sentence, which is in my second for loop
The classes (kernel and the convolute) will be provided down after my code.
Thank You!
public static void main(String[] args)
{
Kernel kernel = new Kernel();
Convolute convolute = new Convolute();
int[][] matrixA = convolute.MATRIX_A;
int[][] kernelVertical = kernel.VERTICAL;
int[][] resultArray = new int[4][4];
int tempMatrix = 0, sumMatrix = 0; // declare temporary matrix and sumMatrix to take all the sum of each product array
int matrixRowA = 0, matrixColumnA = 0; // declare variable for matrix row and column
int convoluteRowControl = 2, convoluteColumnControl = 2; // this variable is to control moving of the kernel through the convolute
while(convoluteRowControl < matrixA.length) // while loop stops when convoluteRowControl points to 6
{
for(int kernelRow = 0; kernelRow < kernelVertical.length; kernelRow++) // this loop will stop when kernelRow is 3
{
for(int kernelColumn = 0; kernelColumn < kernelVertical[kernelRow].length; kernelColumn++) // this loop will stop when kernelColumn is 3
{
tempMatrix = matrixA[matrixRowA][matrixColumnA] * kernelVertical[kernelRow][kernelColumn]; // ERROR IS HERE!!
sumMatrix += tempMatrix; // sum all of the matrix calculated
matrixColumnA++; // re-initialize matrixColumnA to move to the next column element in matrixA
}
matrixRowA++; // re-initialize matrixRowA to move to the next row element in matrixA
matrixColumnA = convoluteColumnControl - 2; // re-initialize matrixColumnA back to the original specified range
}
for(int row = 0; row < resultArray.length; row++) // this loop is used to store sumMatrix calculated in the above loop to each element of the array
{ // loop stops at 5
for(int column = 0; column < resultArray[row].length; column++)
{
resultArray[row][column] = sumMatrix; // store sumMatrix into each element of the array
}
}
++convoluteColumnControl; // re-initialize convoluteColumnControl so that the kernel can move to the next column
if(matrixColumnA < 5) // if kernel get to the last column of its size, reset the row and move to the next column again
{ // this will stop when kernel get to the final column of the convolute
matrixRowA = convoluteRowControl - 2; // reset row back to the the top kernel
matrixColumnA = convoluteColumnControl - 2; // set new starting limit for the column in the kernel
}
if(matrixColumnA == 5) // when matrixColumnA is 5 (which means the final column of the convolute) this IF is executed
{ // to set the new row for the kernel
++convoluteRowControl; // convolteRowControl increase by 1 to set a new row limit for the kernel in convolution
matrixRowA = convoluteRowControl - 2; // reset matrixRowA equivalent to the starting of the new kernel
}
}
}
public class Convolute
{
/*
* ARRAY_A contains a 6x6 matrix
*/
public static final int[][] MATRIX_A =
{
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0},
{10, 10, 10, 0, 0, 0}
};
}
public class Kernel
{
/*
* HORIZONTAL - A kernel that detects horizontal lines.
*/
public static final int[][] HORIZONTAL =
{
{ 1, 1, 1},
{ 0, 0, 0},
{-1, -1, -1}
};
/*
* VERTICAL - A kernel that detects vertical lines.
*/
public static final int[][] VERTICAL =
{
{ 1, 0, -1},
{ 1, 0, -1},
{ 1, 0, -1}
};
}

Related

How to Convert Python Code to Java without numpy

I have a method in Python that makes use of OpenCV to remove the background from an image. I want the same functionality to work with android's version of OpenCV but I just cant seem to wrap my head around how the arrays work and how I can process them.
This is what I have so far in Java :
private Bitmap GetForeground(Bitmap source){
source = scale(source,300,300);
Mat mask = Mat.zeros(source.getHeight(),source.getWidth(),CvType.CV_8U);
Mat bgModel = Mat.zeros(1,65,CvType.CV_64F);
Mat ftModel = Mat.zeros(1,65,CvType.CV_64F);
int x = (int)Math.round(source.getWidth()*0.1);
int y = (int)Math.round(source.getHeight()*0.1);
int width = (int)Math.round(source.getWidth()*0.8);
int height = (int)Math.round(source.getHeight()*0.8);
Rect rect = new Rect(x,y, width,height);
Mat sourceMat = new Mat();
Utils.bitmapToMat(source, sourceMat);
Imgproc.grabCut(sourceMat, mask, rect, bgModel, ftModel, 5, Imgproc.GC_INIT_WITH_RECT);
int frameSize=sourceMat.rows()*sourceMat.cols();
byte[] buffer= new byte[frameSize];
mask.get(0,0,buffer);
for (int i = 0; i < frameSize; i++) {
if (buffer[i] == 2 || buffer[i] == 0){
buffer[i] = 0;
}else{
buffer[i] = 1 ;
}
}
byte[][] sourceArray = getMultiChannelArray(sourceMat);
byte[][][] reshapedMask = ReshapeArray(buffer, sourceMat.rows(), sourceMat.cols());
return source;
}
private byte[][][] ReshapeArray(byte[] arr, int rows, int cols){
byte[][][] out = new byte[cols][rows][1];
int index=0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
out[i][j][0] = arr[index];
index++;
}
}
return out;
}
public static byte[][] getMultiChannelArray(Mat m) {
//first index is pixel, second index is channel
int numChannels=m.channels();//is 3 for 8UC3 (e.g. RGB)
int frameSize=m.rows()*m.cols();
byte[] byteBuffer= new byte[frameSize*numChannels];
m.get(0,0,byteBuffer);
//write to separate R,G,B arrays
byte[][] out=new byte[frameSize][numChannels];
for (int p=0,i = 0; p < frameSize; p++) {
for (int n = 0; n < numChannels; n++,i++) {
out[p][n]=byteBuffer[i];
}
}
return out;
}
The python code I want to recreate :
image = cv2.imread('Images/handheld.jpg')
image = imutils.resize(image, height = 300)
mask = np.zeros(image.shape[:2],np.uint8)
bgModel = np.zeros((1,65),np.float64)
frModel = np.zeros((1,65),np.float64)
height, width, d = np.array(image).shape
rect = (int(width*0.1),int(height*0.1),int(width*0.8),int(height*0.8))
cv2.grabCut(image, mask, rect, bgModel,frModel, 5,cv2.GC_INIT_WITH_RECT)
mask = np.where((mask==2) | (mask == 0),0,1).astype('uint8')
image = image*mask[:,:,np.newaxis]
I have no idea how to convert the last two lines of the python code. If there is a way to just run python clean on an android device within my own project that would also be awesome.
At this point, you should consider talking a look to SL4A project which would allow you run your Python code on Android through java app.
Here are interesting links :
https://github.com/damonkohler/sl4a
https://norwied.wordpress.com/2012/04/11/run-sl4a-python-script-from-within-android-app/
http://jokar-johnk.blogspot.com/2011/02/how-to-make-android-app-with-sl4a.html
Let's see both the commands and try to convert them to Java API calls. It may not be simple 2 line in code.
mask = np.where((mask==2) | (mask == 0),0,1).astype('uint8')
In the above command, we are creating a new image mask which has uint data type of pixel values. The new mask matrix would have value 0 for every position where previous mask has a value of either 2 or 0, otherwise 1. Let's demonstrate this with an example:
mask = [
[0, 1, 1, 2],
[1, 0, 1, 3],
[0, 1, 1, 2],
[2, 3, 1, 0],
]
After this operation the output would be:
mask = [
[0, 1, 1, 0],
[1, 0, 1, 1],
[0, 1, 1, 0],
[0, 1, 1, 0],
]
So this above command is simply generating a binary mask with only 0 and 1 values. This can replicated in Java using Core.compare() method as:
// Get a mask for all `1` values in matrix.
Mat mask1vals;
Core.compare(mask, new Scalar(1), mask1vals, Core.CMP_EQ);
// Get a mask for all `3` values in matrix.
Mat mask3vals;
Core.compare(mask, new Scalar(3), mask3vals, Core.CMP_EQ);
// Create a combined mask
Mat foregroundMask;
Core.max(mask1vals, mask3vals, foregroundMask)
Now you need to multiply this foreground mask with the input image, to get final grabcut image as:
// First convert the single channel mat to 3 channel mat
Imgproc.cvtColor(foregroundMask, foregroundMask, Imgproc.COLOR_GRAY2BGR);
// Now simply take min operation
Mat out;
Core.min(foregroundMask, image, out);

Java 2D array, possible to set individual size?

Quick question about Java 2D arrays; For my tile-based, top-down, 2D game (using swing) I use
a 2D array to create a map, like this
public int[][] createMap(){
return new int[][]{
{0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}};
}
I then use this in my gameComponents class where I draw the individual tiles unto the map, like this
protected void paintComponent(Graphics g){
super.paintComponent(g);
for (int row = 0; row < game.getMap().getWidth(); row++) {
for (int col = 0; col < game.getMap().getHeight(); col++) {
g.drawImage(tile.getTileImage().get(values()[game.getMap().getMapArray()[col][row]]), row * SIZE,
col * SIZE, this);
}
} }
(where size is the size of a tile)
This works, and it correctly draws each tile to the map as expected, however
this also causes a problem for collision detection. As you may have noted, while I do define the size between the tiles in draw method, it is not defined in the array at all. Which, as you'd imagine, raises issues when checking for collision as the drawn tile is not where the tile is in the 2D array (due to size offset).
This is the code I use for checking collision (of course, not working due to ArrayIndexOutofbounds).
public boolean collisionDetected(int xDirection, int yDirection, Game game, Player player){
for (int row = 0; row < game.getMap().getHeight() * 16; row ++){
for (int col = 0; col < game.getMap().getWidth() * 16; col++) {
System.out.println(col + xDirection + player.getPositionX());
if(game.getMap().getTile(col + xDirection + player.getPositionX() ,
row + yDirection + player.getPositionY()) == Tiles.GRASS ){
System.out.println("COLLISION DETECTED");
return true;
}
}
}
return false;
}
This method uses a method within the map class that returns the tile on that
specific coordinate, like this
public Tiles getTile(int col,int row){
return Tiles.values()[mapArray[col][row]];
}
And, of course, as the 2D array doesn't know of the size offset, it just throws
an arrayindexoutofbound.
My question is, is it possible to define a 2D map array with the size of a tile in-mind? I appreciate any help & input I can get, after-all I am here to learn!
Extra clarification: All the tiles are in an enum class (i.e AIR, GRASS, STONE...). Also worth noting that the player position is not bound by an array, I merely move it the amount of pixels I want it to move.
Thanks in advance!
This method uses a method within the map class that returns the tile on that specific coordinate, like this
public Tiles getTile(int col,int row){
return Tiles.values()[mapArray[col][row]];
}
So if you have a "coordinate", why do you call the parameters col/row?
If you have a 10x10 grid and each tile is 20 pixels then the grid size is 200x200 so you could have x/y values in the range 0-199
So if you have a coordinate of 25x35 you would simply calculate the row/col values as:
int row = 35 / 20;
int column = 25 / 20;
So your method would be something like :
public Tiles getTile(int x, int y)
{
int row = y / 20;
int column = x / 20;
return Tiles.values()[mapArray[row][column]];
}

Java Iterating into array for different orientations

I'm stitching a bitmap from a layout array, that puts the a larger bitmap together as a guide. Using multiple bitmaps into one bitmap. What I rotate the whole bitmap, my solution is to restitch it but have the array account for this rotation. The making of the bitmap is determined by the order of the array. The stitching assumes that the array starts from zero and that is the first index or the left top most corner and then goes to the right to the end and goes to beginning of the next row. I would like to have a 90, 180, 270, and 360 functions to call on. I'm thinking 360 is easy I iterate backwards. I'm using 11 by 11 which is constant.
For example
0, 1, 3, 4
5, 6, 7, 8,
9, 10, 11, 12
13, 14, 15, 16
when I rotate 90
4, 8, 12, 16
3, 7, 11, 15
1, 6, 10, 14
0, 5, 9, 13
Try this. This may have performance impact but its a simple solution.
import java.util.Arrays;
public class RotateMatrix {
public static void main(String[] args) {
int original[][] = { { 0, 1, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
printArray(original);
System.out.println("After 90 Degree");
printArray(rotate(original, 90));
System.out.println("After 180 Degree");
printArray(rotate(original, 180));
System.out.println("After 270 Degree");
printArray(rotate(original, 270));
System.out.println("After 360 Degree");
printArray(rotate(original, 360));
}
private static int[][] rotate(int[][] original, int angle) {
int[][] output = original;
int times = 4 - angle/90;
for(int i=0; i<times; i++){
output = rotate(output);
}
return output;
}
private static int[][] rotate(int[][] original) {
int n = original.length;
int m = original[0].length;
int[][] output = new int[m][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
output[j][n - 1 - i] = original[i][j];
return output;
}
private static void printArray(int[][] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(Arrays.toString(array[i]));
}
}
}
This rotates the array anti-clockwise direction just as in your example. However if you want to change this to clockwise just change int times = 4 - angle/90; to int times = angle/90; in rotate(int[][] original, int angle) method.

Knights tour backtracking lasts too long

How long does it last to solve the knights tour problem with backtracking on an 8x8 board? Because my algorithm already computes somehow too long and it seems, like it wont finish. But when I try a 6x6, or 5x5 board, it finishes successfully.
the code:
class KnightsTour{
private boolean[][] board;
private int count, places;
private static final Point[] moves = new Point[]{
new Point(-2, -1),
new Point(-2, 1),
new Point(2, -1),
new Point(2, 1),
new Point(-1, -2),
new Point(-1, 2),
new Point(1, -2),
new Point(1, 2)
};
public KnightsTour(int n) {
board = new boolean[n][n];
places = n*n;
count = 0;
}
public boolean ride(int x, int y) {
board[x][y] = true;
count++;
if (count == places) {
return true;
}
for (Point p : moves) {
int nextX = x + p.x;
int nextY = y + p.y;
if (nextX < 0 || nextX >= board.length || nextY < 0 || nextY >= board.length || board[nextX][nextY]) {
continue;
}
if (ride(nextX, nextY)) {
return true;
}
}
board[x][y] = false;
count--;
return false;
}
}
I came across the same problem. Everything runs smoothly till n=7 and suddenly it takes forever to calculate for n=8. I hope this helps someone :)
The problem lies with the order in which you are checking for the moves. You are using :
xMove[8] = { -2, -2, 2, 2, -1, -1, 1, 1}
yMove[8] = { -1, 1, -1, 1, -2, 2, -2, 2}
If you plot these vectors in the 2D plane, they are haphazardly placed. In other words, they are not ordered in either a clockwise or an anti-clockwise manner. Consider this instead :
xMove[8] = { 2, 1, -1, -2, -2, -1, 1, 2 }
yMove[8] = { 1, 2, 2, 1, -1, -2, -2, -1 }
If you plot these vectors, they are neatly arranged in an anticlockwise circle.
Somehow this causes the recursion to run much quickly for large values of n. Mind you, it still takes forever to calculate for n=9 onwards.

Using Number Randoms in Arrays that randomize

I am making a small class for a little project. It's a text based RPG game and I am trying to create a drop class for when NPC's die. I have create a couple Math.random methods (which are exactly the same, just differently named for my convenience.) to drop random amounts for an item id (name) and to get the rarity of the item dropped. It all works fine, but it only randomizes one time (on startup or run) and it won't randomize the amounts after that. I am also randomizing it between 2 numbers, for example, 25 and 50, the random not going lower then 25 or higher then 50.
My question is: How can I randomize a integer in a 2D Array or a general array after each time a NPC dies, so the random number that is first obtained changes and doesn't stay the same. Because right now, it stays at the number choose. if the number is 25, then the next npc I kill, the amount would still be 25.. and 25.. and 25.. and so on. I need it to randomize or change.
Please help, thank you.
public class DropConfig {
private static final int
ALWAYS = 0,
VERY_COMMON = rate(1, 9),
COMMON = rate(10, 20),
UNCOMMON = rate(30, 40),
RARE = rate(50, 60),
VERY_RARE = rate(70, 80),
SUPER_RARE = rate(90, 100);
public static final int[][] NPC_DROPS = {
// Normal NPC's
{1, 526, 1, ALWAYS},
{2, 526, 1, ALWAYS},
{3, 526, 1, ALWAYS},
{1, 995, drop(1, 50), ALWAYS},
{2, 995, drop(1, 50), ALWAYS},
{3, 995, drop(1, 50), ALWAYS},
// Moderate NPC's
{9, 526, 1, ALWAYS},
{9, 995, drop(250, 500), UNCOMMON},
{9, 555, drop(2, 7), VERY_COMMON},
{9, 995, drop(5, 50), VERY_COMMON},
{9, 1050, 1, RARE},
};
public static int rate(int min, int max) {
return 1 + (int)(Math.random() * ((max - min) + 1));
}
//Same as rate, different name for looks.
public static int drop(int min, int max) {
return 1 + (int)(Math.random() * ((max - min) + 1));
}
Heres where I call the drops method
public void npcDeath() {
int npc = 0;
if (npc == null)
return;
for(npc = 0; npc < DropConfig.NPC_DROPS.length; npc++) {
if(npc == DropConfig.NPC_DROPS[npc][0]) {
if(Misc.random(DropConfig.NPC_DROPS[npc][3]) == 0) { //Drops ALWAYS item
Item(DropConfig.NPC_DROPS[npc][1], DropConfig.NPC_DROPS[npc][2]);
}
}
}
}
If I understand correctly, you would like the elements of the NPC_DROPS array initialized with a call to drop() to be reinitialized each time this NPC_DROPS array is used.
Well, NPC_DROPS is a constant, so it can't change. Generate it each time it's accessed, using a method:
public static int[][] generateNpcDrops(){
return new int[][] {
// Normal NPC's
{1, 526, 1, ALWAYS},
{2, 526, 1, ALWAYS},
{3, 526, 1, ALWAYS},
{1, 995, drop(1, 50), ALWAYS},
{2, 995, drop(1, 50), ALWAYS},
{3, 995, drop(1, 50), ALWAYS},
// Moderate NPC's
{9, 526, 1, ALWAYS},
{9, 995, drop(250, 500), UNCOMMON},
{9, 555, drop(2, 7), VERY_COMMON},
{9, 995, drop(5, 50), VERY_COMMON},
{9, 1050, 1, RARE},
}
}
...
public void npcDeath() {
int npc = 0;
if (npc == null)
return;
int[][] npcDrops = DropConfig.generateNpcDrops();
for(npc = 0; npc < npcDrops.length; npc++) {
if(npc == npcDrops[npc][0]) {
if(Misc.random(npcDrops[npc][3]) == 0) { //Drops ALWAYS item
Item(c, npcDrops[npc][1], npcDrops[npc][2]);
}
}
}
}
You want to place functions as constants. You can do this in a language like Scala naturally, but in Java you have to work a little harder.
In every case, you need to call a function to get the actual value.
You can use enum and anonymous methods, but the simplest way/hack is to encode your ranges.
public static int rate(int min, int max) { // same for drop.
int range = max - min;
return (range << 16) | (min & 0xFFFF);
}
public static int eval(int minMax) {
int min = (short) minMax;
int range = (short) (minMax >> 16);
if (range == 0)
return min; // plain number.
else
return min + (int) (Math.random() * (range + 1));
}
You need to call eval() to turn your encoded range into a random number.
Creating an instance of Random with the same seed you will get the same 'random' number. Have you considered using SecureRandom? The difference between SecureRandom and Random is that SecureRandom produces non-deterministic output on each call.

Categories