Convolution produces a very dark image - java

Edit:
I included an example of k value. Also to be clear I produce three separate arrays from an RGB image . I also include code for loading the image
public static final int[][] SHARPEN = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
Load image
BufferedImage inputImage = ImageIO.read(new File("bridge-rgb.png")); // load the image from this current folder
When I convolute an image in java using 3*3 kernel, the resultant image produced has some of the properties that you would expect from the given kernel but is extremely dark, black being the dominant colour. If I process the image with an identity kernel then identity is returned so I guess that means that Ive selected the correct setting for creating a bufferedImage and hence the problem must be with my convolution algorithm, however I did test the convolution algorithm with a test array and it does seem to be producing accurate output. I wonder could any one make any comment on what I have or point me in the right direction?
for (int j = 0; j < kernelWidth; ++j) {
try {
output+=(input[y-1][x-1+j] * k[0][j]);
counter++;
}catch(Exception e) {
continue;
}
}
for (int j = 0; j < kernelWidth;++j) {
try {
output+=(input[y][x-1+j] * k[1][j]);
counter1++;
}catch(Exception e) {
continue;
}
}
for (int j = 0; j < kernelWidth;++j) {
try {
output+=(input[y+1][x-1+j] * k[2][j]);
counter2++;
}catch(Exception e) {
continue;
}
}
if((output>>bitshiftValue)>255) {
return ((255& 0xff)<<bitshiftValue);
}
else if ((output>>bitshiftValue)<0) {
return 0;
}else {
return output;
} }
I got the arrays to be convoluted with the following method
private static int[][] convertTo2DWithoutUsingGetRGBgreen(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
int[][] result = new int[height][width];
final int pixelLength = 4;
for (int pixel = 0, row = 0, col = 0; pixel + 3 < pixels.length; pixel += pixelLength) {
result[row][col] = ((int) ((pixels[pixel + 2] & 0xff) )<<8);
col++;
if (col == width) {
col = 0;
row++;
}
}
return result;
}
and post convolution I pimply added them together like so
int[][] finalConv = new int[convRedArray.length][convRedArray[0].length];
for(int c =0; c<convRedArray.length;c++) {
for(int p =0;p<convRedArray[0].length;p++) {
finalConv[c][p]=(convBlueArray[c][p])+(convGreenArray[c[p])+(convRedArray[c][p]);

Related

Assimp skeletal animation becomes a triangle mess

I've been trying to animate a model in OpenGl using Assimp.
The result of my attempts is
this.
Loading bones:
List<Bone> getBones(AIMesh mesh) {
List<Bone> bones = new ArrayList<>();
for (int i = 0; i < mesh.mNumBones(); i++) {
AIBone aiBone = AIBone.create(mesh.mBones().get(i));
Bone bone = new Bone(aiBone.mName().dataString());
bone.setOffset(aiMatrixToMatrix(aiBone.mOffsetMatrix()).transpose());
bones.add(bone);
}
return bones;
}
Loading vertices:
VertexData processVertices(AIMesh mesh) {
float[] weights = null;
int[] boneIds = null;
float[] vertices = new float[mesh.mNumVertices() * 3];
boolean calculateBones = mesh.mNumBones() != 0;
if (calculateBones) {
weights = new float[mesh.mNumVertices() * 4];
boneIds = new int[mesh.mNumVertices() * 4];
}
int i = 0;
int k = 0;
for (AIVector3D vertex : mesh.mVertices()) {
vertices[i++] = vertex.x();
vertices[i++] = vertex.y();
vertices[i++] = vertex.z();
//bone data if any
if (calculateBones) {
for (int j = 0; j < mesh.mNumBones(); j++) {
AIBone bone = AIBone.create(mesh.mBones().get(j));
for (AIVertexWeight weight : bone.mWeights()) {
if (weight.mVertexId() == i - 3) {
k++;
boneIds[k] = j;
weights[k] = weight.mWeight();
}
}
}
}
}
What am I doing wrong.
Are all the matrices required for the bind pose or can I use only the offset for testing?
If I get you code right you do not get the inidecs by the faces, right? You need to iterate over the faces of your mesh to get the correct inidices, if I get the concept you are using right.

What am I doing wrong with my image denoising method?

I've been trying to denoise my image by using a median filter as described in this article
I'm only doing one pass until I get this thing working. The result is largely a washed out image, as seen below.
A minimal working version of my code is below:
import java.awt.image.BufferedImage;
import java.util.Arrays;
public class Denoise {
public static void main(String args[]) {
String directory = "C:\\Users\\Speedy Octopus\\Desktop\\Place Car Folders Here\\Original\\15.JPG";
BufferedImage image = ImageUtility.loadImage(directory);
for (int iterationCount = 0; iterationCount < 1; iterationCount++){
for (int i = 1; i < image.getWidth()-1; i++) {
for (int j = 1; j < image.getHeight()-1; j++) {
image.setRGB(i, j, getMedianPixelValue(image, i, j));
}
}
}
String directory2 = "C:\\Users\\Speedy Octopus\\Desktop\\Place Car Folders Here\\Original\\152.JPG";
Controller.saveImage(image, directory2);
}
public static int getMedianPixelValue(BufferedImage image, int i, int j) {
int[] surroundingPixels = new int[8];
int iter = 0;
for (int q = i-1; q<=i+1; q++) {
for (int r = j-1; r<=j+1;r++) {
if (!(q == i && r == j)) {
surroundingPixels[iter] = image.getRGB(q, r);
iter++;
}
}
}
Arrays.sort(surroundingPixels);
int medianIndex = surroundingPixels.length/2;
int medianPixel = surroundingPixels[medianIndex];
return medianPixel;
}
}
As I answered in this question Applying Mean filter on an image using java getRGB "Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB)" so you have to extract and remove the alpha (A) component before you do any comparisons:
pixel=image.getRGB(i, j)&0x00ffffff;
in the media sorting etc
And you can extract the R, G, and B and process them separately, or do the comparison on the whole pixel RGB - you can experiment either way.

Paint Fill multidimensional array

My goal is a "paint fill" function that one might see on many image editing programs. That is, given a screen (represented by a two-dimensional array of colors), a point, and a new color, fill in the surrounding area until the color changes from the original color.
I've implemented it for a 2D array, and here is the code :
public static void paint (int [][] screen,int OldColor,int NewColor,int y,int x)
{
if(y>screen.length-1||y<0||x>screen[0].length||x<0||screen[y][x]!=OldColor)
return;
screen[y][x]=NewColor;
paint(screen,OldColor,NewColor,y-1,x);
paint(screen, OldColor, NewColor, y+1, x);
paint(screen, OldColor, NewColor, y, x-1);
paint(screen, OldColor, NewColor, y, x+1);
}
But I want to implement it for multidimensional arrays like 3D that could be solved by adding:
paint(screen, OldColor, NewColor, y, x,z-1);
paint(screen, OldColor, NewColor, y, x,z+1);
But imagine the array is 100 D... How can I solve this problem?
Thanks to #Spektre's suggestion about the structure of the points, I managed to write a simple N-Dimensional floodfill.
Instead of images, I used char matrix to simplify the coding. Changing it to int as color value and some changes in other matrix's data type, will do the 100D for you :)
In this simple program, I try to fill all "A"'s with "B" and it fill all of connected char values similar to ants nest. You can trace the connections between A's using other layers to see the fill path.
In second image (Im1, add intentionally added a B and then added an A above it which is not accessible from fill point) and it worked fine as well.
package test;
import java.awt.Point;
import java.util.LinkedList;
import java.util.Queue;
/**
*
* #author Pasban
*/
public class NDFloodFill {
public int N1 = 8; // width
public int N2 = 6; // height
public int N = 3; // number of layers
public ImageData[] images = new ImageData[N];
public static void main(String[] args) {
NDFloodFill ndf = new NDFloodFill();
//print original data
//ndf.print();
ndf.fill(0, 0, 0, 'A', 'B');
ndf.print();
}
public NDFloodFill() {
String im0 = ""
+ "AA...A..\n"
+ ".....A..\n"
+ "....AA..\n"
+ "........\n"
+ "........\n"
+ "...AA.AA";
String im1 = ""
+ ".A..A...\n"
+ "....B...\n"
+ "..AAA...\n"
+ "........\n"
+ "...AA.A.\n"
+ "..AA..A.";
String im2 = ""
+ ".A......\n"
+ ".AA.....\n"
+ "..A.....\n"
+ "..A.....\n"
+ "..A.AAA.\n"
+ "..A.....";
images[0] = new ImageData(im0, 0);
images[1] = new ImageData(im1, 1);
images[2] = new ImageData(im2, 2);
}
private void print() {
for (int i = 0; i < N; i++) {
System.out.println(images[i].getImage());
}
}
private void fill(int x, int y, int index, char original, char fill) {
Queue<PixFill> broadCast = new LinkedList<>();
broadCast.add(new PixFill(new Point(x, y), index));
for (int i = 0; i < N; i++) {
images[i].reset();
}
while (!broadCast.isEmpty()) {
PixFill pf = broadCast.remove();
Queue<PixFill> newPoints = images[pf.index].fillArea(pf.xy, original, fill);
if (newPoints != null) {
broadCast.addAll(newPoints);
}
}
}
public class PixFill {
Point xy;
int index;
public PixFill(Point xy, int index) {
this.xy = xy;
this.index = index;
}
#Override
public String toString() {
return this.xy.x + " : " + this.xy.y + " / " + this.index;
}
}
public class ImageData {
char[][] pix = new char[N1][N2];
boolean[][] done = new boolean[N1][N2];
int index;
public ImageData(String image, int index) {
int k = 0;
this.index = index;
for (int y = 0; y < N2; y++) { // row
for (int x = 0; x < N1; x++) { // column
pix[x][y] = image.charAt(k++);
}
k++; // ignoring the \n char
}
}
public void reset() {
for (int y = 0; y < N2; y++) {
for (int x = 0; x < N1; x++) {
done[x][y] = false;
}
}
}
public String getImage() {
String ret = "";
for (int y = 0; y < N2; y++) { // row
String line = "";
for (int x = 0; x < N1; x++) { // column
line += pix[x][y];
}
ret += line + "\n";
}
return ret;
}
public Queue<PixFill> fillArea(Point p, char original, char fill) {
if (!(p.x >= 0 && p.y >= 0 && p.x < N1 && p.y < N2) || !(pix[p.x][p.y] == original)) {
return null;
}
// create queue for efficiency
Queue<Point> list = new LinkedList<>();
list.add(p);
// create broadcasting to spread filled points to othwer layers
Queue<PixFill> broadCast = new LinkedList<>();
while (!list.isEmpty()) {
p = list.remove();
if ((p.x >= 0 && p.y >= 0 && p.x < N1 && p.y < N2) && (pix[p.x][p.y] == original) && (!done[p.x][p.y])) {
//fill
pix[p.x][p.y] = fill;
done[p.x][p.y] = true;
//look for neighbors
list.add(new Point(p.x - 1, p.y));
list.add(new Point(p.x + 1, p.y));
list.add(new Point(p.x, p.y - 1));
list.add(new Point(p.x, p.y + 1));
// there will not be a duplicate pixFill as we always add the filled points that are not filled yet,
// so duplicate fill will never happen, so do pixFill :)
// add one for upper layer
if (index < N - 1) {
broadCast.add(new PixFill(p, index + 1));
}
// add one for lower layer
if (index > 0) {
broadCast.add(new PixFill(p, index - 1));
}
//layers out of range <0, N> can be filtered
}
}
return broadCast;
}
}
}
Avoid recursive functions! Use a queue instead to flood fill the image ith.
On which image you want to start filling?
check the image color on ith image and add that point to your list.
Later on check if you can go up or down from the stored point to (i+1)th or (i-1)th image and repeat this process from there.
This is a raw idea, but all you may need is this.
Plus, you need to have an array for each level to check if you have filled that pixel for that image or not. So you will escape from infinite loop :)
Check this for flood fill using queue:
Flood Fill Optimization: Attempting to Using a Queue
Salivan is right with his suggestions but he did not grasp the real problem you are asking about. For arbitrary dimensionality you need to change the point structure from notation like pnt.x,pnt.y,pnt.z to pnt[0],pnt[1],pnt[2] then there are few approaches how to handle this:
fixed limit size padded with zeros
so handle all like 10D (if 10D is maximal dimensionality used) and fill unused axises with zeros. This is slow ugly,painfully demanding on memory and limiting max dimensionality.
use nested for loop (for initializations and more)
look here: rasterize and fill a hypersphere
many multidimensional operations require nested loops this one has arbitrary depth. You can look at it as an increment function of multi digit number where each digit represents axis in your space.
use normal for loop for neighbors generation in N-D
// point variables
int p[N],q[N];
// here you have actual point p and want to find its neighbors
for (int i=0;i<N;i++)
{
for (int j=0;i<N;i++) q[j]=p[j]; // copy point
q[i]--;
// add q to flood fill
q[i]+=2;
// add q to flood fill
}

Image filter - Convolution

I am trying to implement image filter ( using convulution). I've spent all day trying to figure out what's going on and I cannot find a mistake. The filter works only when I use it to blur the image. In other cases it doesn't work properly: For example this is the original picture(before filtering):
And this is the picture after filtering with this matrix:
I use Marvin Image Processing Framework and jblas library in my code:
public class FiltrySploty extends MarvinAbstractImagePlugin {
#Override
public void load() {
}
#Override
public MarvinAttributesPanel getAttributesPanel() {
return null;
}
#Override
public void process(
MarvinImage imageIn,
MarvinImage imageOut,
MarvinAttributes attributesOut,
MarvinImageMask mask,
boolean previewMode) {
double norm=0;
DoubleMatrix filter = (DoubleMatrix)getAttribute("filter");
for ( int i = 0; i < filter.getRows();i++)
{
for ( int j = 0; j < filter.getColumns();j++)
{
norm=norm+filter.get(i, j);
}
}
int marginx = ((filter.getRows()-1)/2);
int marginy = ((filter.getColumns()-1)/2);
for (int x = marginx; x < imageIn.getWidth()-marginx; x++) {
for (int y = marginy; y < imageIn.getHeight()-marginy; y++) {
double SumRed=0;
double SumGreen=0;
double SumBlue=0;
for ( int i = x-marginx,k=0 ; k < filter.getRows();i++,k++)
{
for ( int j = y-marginy, l=0 ; l <filter.getColumns();j++,l++)
{
SumRed= SumRed+(filter.get(k, l)*imageIn.getIntComponent0(i, j));
SumGreen= SumGreen+(filter.get(k, l)*imageIn.getIntComponent1(i, j));
SumBlue= SumBlue+(filter.get(k, l)*imageIn.getIntComponent2(i, j));
}
}
SumRed = SumRed/norm;
SumGreen = SumGreen/norm;
SumBlue = SumBlue/norm; // normalization
if(SumRed>255.0) SumRed=255.0;
else if(SumRed<0.0) SumRed=0.0;
if(SumGreen>255.0) SumGreen=255.0;
else if(SumGreen<0.0) SumGreen=0.0;
if(SumBlue>255.0) SumBlue=255.0;
else if(SumBlue<0.0) SumBlue=0.0;
imageOut.setIntColor(x, y, (int)(SumRed), (int)(SumGreen), (int)(SumBlue));
}
}
}
}
Seeing the effect of filtering I suppose that the SumRed, SumGreen and SumBlue are out of range and they are setting to 255 or 0 values. But I have no idea why.

Reading tiff raster data

I'm reading a 2048X2048 pixels tiff file using the method below:
private static int[][] convertTo2DWithoutUsingGetRGB(BufferedImage image) {
final short[] pixels = ((DataBufferUShort) image.getRaster().getDataBuffer()).getData();
int[][] data = new int[2048][2048];
int col = 0;
int row = 0;
int blockSize = 2048;
for (int i=0; i<pixels.length; i++) {
data[col][row] = pixels[i];
row++;
if (row == blockSize) {
col++;
row = 0;
}
}
return data;
}
But I keep getting negative values on my array, if I use gdal with python, for example:
import gdal # Tiff Image Read
def getArrayFromImage(fileName):
img = gdal.Open(fileName)
return img.ReadAsArray().astype(int)
I get only positive values. In the java method above is there a treatment needed in the raw value to be a valid pixel for the tiff image?
Not sure why, but solved the issue by adding 65536 to the value if it is negative.
int j = pixels[i];
if (j < 0) {
j += 65536;
}
data[col][row] = j;

Categories