ImageJ API: Combining images - java

Using the ImageJ api, I'm trying to save an composite image, made up of several images laid out side by side.
I've got code that loads ImagePlus objs, and saves them. But I can't figure how to paste an image into another image.

I interpret the problem as taking multiple images and stitching them together side by side to form a large one where the images may have different dimensions. The following incomplete code is one way of doing it and should get you started.
public ImagePlus composeImages(ArrayList<ImagePlus> imageList){
int sumWidth = 0;
int maxHeight = 0;
for(ImagePlus imp : imageList){
sumWidth = sumWidth +imp.getWidth();
if(imp.getHeight() > maxHeight)
maxHeight = imp.getWidth();
}
ImagePlus impComposite = new ImagePlus();
ImageProcessor ipComposite = new ShortProcessor(sumWidth, maxHeight);
for(int i=0; i<sumWidth; i++){
for(int j=0; j<sumWidth; j++){
ipComposite.putPixelValue(i, j, figureOutThis);
}
}
impComposite.setProcessor(ipComposite);
return impComposite;
}
You need to write an algorithm to find the pixel value (figureOutThis) to put in the composite image at i,j. That is pretty trivial if all images have the same width and a little bit more work otherwise. Happy coding
Edit:
I should add that I am assuming they are also all short images (I work with medical grayscale). You can modify this for other processors

This code combines/stitches a grid of images:
It assumes the images are all of the same dimensions.
ImagePlus combine(List<List<ImagePlus>> imagesGrid) {
checkArgument(
!imagesGrid.isEmpty() && !imagesGrid.get(0).isEmpty(), "Expected grid to be non-empty");
checkArgument(
imagesGrid.stream().map(List::size).distinct().count() == 1,
"Expected all rows in the grid to be of the same size");
checkArgument(
imagesGrid.stream().flatMap(List::stream).map(ImagePlus::getWidth).distinct().count() == 1,
"Expected all images to have the same width");
checkArgument(
imagesGrid.stream().flatMap(List::stream).map(ImagePlus::getHeight).distinct().count() == 1,
"Expected all images to have the same height");
int rows = imagesGrid.size();
int cols = imagesGrid.get(0).size();
int singleWidth = imagesGrid.get(0).get(0).getWidth();
int singleHeight = imagesGrid.get(0).get(0).getHeight();
int combinedWidth = singleWidth * cols;
int combinedHeight = singleHeight * rows;
ImageProcessor processor = new ColorProcessor(combinedWidth, combinedHeight);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
ImagePlus image = imagesGrid.get(row).get(col);
int offSetWidth = col * singleWidth;
int offsetHeight = row * singleHeight;
for (int w = 0; w < singleWidth; w++) {
for (int h = 0; h < singleHeight; h++) {
processor.putPixel(w + offSetWidth, h + offsetHeight, image.getPixel(w, h));
}
}
}
}
ImagePlus combinedImage = new ImagePlus();
combinedImage.setProcessor(processor);
return combinedImage;
}

Related

Java - Problem with saving buffered image to file rotates 90 degrees

I've been trying to complete a method that saves Color[][] to jpg image files, however the solutions will result in the output file being rotate 90 degrees, I've tried looking for the problem but does not come obvious to me, as well as other people with similar solutions doesn't seem to have the same problems.
Any help is greatly appreciated!
private Color[][] image; // assume this field has already been populated
public void saveImage() {
BufferedImage saveImage = new BufferedImage(this.image.length,
this.image[0].length,
BufferedImage.TYPE_INT_RGB);
for (int row = 0; row < this.image.length; row++) {
for (int col = 0; col < this.image[row].length; col++) {
saveImage.setRGB(row, col, this.image[row][col].getRGB());
}
}
String fName = UIFileChooser.save();
if (fName==null){return;}
File toFile = new File(fName+".jpg");
try {
ImageIO.write(saveImage,"jpg", toFile);
}catch (IOException e){UI.println("File save error: "+e);}
}
thanks for the helps, it turns out I just had to flip the dimensions and x/y coordinates, below is the fixed version:
private Color[][] image; // assume this field has already been populated
public void saveImage() {
BufferedImage saveImage = new BufferedImage(this.image[0].length,
this.image.length,
BufferedImage.TYPE_INT_RGB);
for (int row = 0; row < this.image.length; row++) {
for (int col = 0; col < this.image[row].length; col++) {
saveImage.setRGB(col, row, this.image[row][col].getRGB());
}
}
String fName = UIFileChooser.save();
if (fName==null){return;}
File toFile = new File(fName+".jpg");
try {
ImageIO.write(saveImage,"jpg", toFile);
}catch (IOException e){UI.println("File save error: "+e);}
}
The signature of the BufferedImage.setRGB method is public void setRGB​(int x, int y, int rgb)
X comes first, then Y. row equals y and col equals x.
So change that line to:
saveImage.setRGB(col, row, this.image[row][col].getRGB());

change color of bitmap

I'm trying to create a function that gets a bitmap and destiny color and returns the colored bitmap (without using paint). I found few ways of doing it but nothing works like I want it to.
The closest solution I was able to find is:
public static Bitmap changeImageColor(Bitmap srcBmp, int dstColor) {
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
float srcHSV[] = new float[3];
float dstHSV[] = new float[3];
Bitmap dstBitmap = Bitmap.createBitmap(width, height, Config.RGB_565);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
Color.colorToHSV(srcBmp.getPixel(col, row), srcHSV);
Color.colorToHSV(dstColor, dstHSV);
// If it area to be painted set only value of original image
dstHSV[2] = srcHSV[2]; // value
int color2=Color.HSVToColor(dstHSV);;
dstBitmap.setPixel(col, row, Color.HSVToColor(dstHSV));
}
}
return dstBitmap;
}
but It doesn't work very well on transparent images as can be seen here (before and after):
Anyone has any other solutions (again without using paint at all)?
You just need to extract alpha and re-apply it after transformation. And use ARGB_8888;
Edited your code to include alpha:
public Bitmap colorize(Bitmap srcBmp, int dstColor) {
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
float srcHSV[] = new float[3];
float dstHSV[] = new float[3];
Bitmap dstBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = srcBmp.getPixel(col, row);
int alpha = Color.alpha(pixel);
Color.colorToHSV(pixel, srcHSV);
Color.colorToHSV(dstColor, dstHSV);
// If it area to be painted set only value of original image
dstHSV[2] = srcHSV[2]; // value
dstBitmap.setPixel(col, row, Color.HSVToColor(alpha, dstHSV));
}
}
return dstBitmap;
}
here is a sample code for change the color for a bitmap:
private BitmapDrawable getColoredBitmap(int color, Context context,
int drawableId) {
Bitmap source = BitmapFactory.decodeResource(context.getResources(),
drawableId);
final Bitmap bitmap = Bitmap.createBitmap(source.getWidth(),
source.getHeight(), Bitmap.Config.ARGB_8888);
for (int i = 0; i < source.getWidth(); i++) {
for (int j = 0; j < source.getHeight(); j++) {
int pixel = source.getPixel(i, j);
// if (pixel == Color.TRANSPARENT) {
//
// } else
if (pixel == Color.WHITE) {
pixel = Color.argb(Color.alpha(pixel),
Color.red(Color.WHITE), Color.green(Color.WHITE),
Color.blue(Color.WHITE));
} else {
pixel = Color.argb(Color.alpha(pixel), Color.red(color),
Color.green(color), Color.blue(color));
}
bitmap.setPixel(i, j, pixel);
}
}
return new BitmapDrawable(context.getResources(), bitmap);
}
You do this:
int alpha=srcBmp.getPixel(col, row);
dstBitmap.setPixel(col, row, Color.HSVToColor(dstHSV));
in which you calculate an alpha (probably incorrectly from the looks of that code) and then don't use it. You are probably going to have to create a Color with HSVToColor, then set the alpha of that color, then use it in setPixel. And you are probably going to have to get the alpha in a similar way because I find it hard to believe a getPixel function only returns the alpha :p

TableView and List Data

I am trying to display a List of icons (which are referred simply by their path) in a TableView that has x-amount of columns and any number of cells that are required to display all the icons.
The plan was to display the icons in such a way that the TableView acts as a "multi-lined" ListView.. so that they go from left to the right.
It's the first time I'm using the TableView control, and I'm a bit confused of how to achieve this.
Thanks for any pointers.
So, as ItachiUchiha suggested, I ended up using a Pagination control with a GridPane, and it works very nicely.
Here's the code if anyone stumbles upon the same thing..
List<String> allEntries = Icons.getAllEntries();
int numCols = 8;
int numRows = 5;
int numPages = allEntries.size() / (numCols * numRows);
Pagination pagination = new Pagination(numPages);
Collections.sort(allEntries);
pagination.setPageFactory(pageIndex -> {
GridPane layout = new GridPane();
for (int y = 0; y < numRows; y++) {
for (int x = 0; x < numCols; x++) {
int index = numCols * y + x + (pageIndex * numCols * numRows);
String path = allEntries.get(index);
Image image = new Image(path, true);
ImageView imageView = new ImageView(image);
imageView.setFitWidth(64);
imageView.setFitHeight(64);
layout.add(imageView, x, y);
imageView.setOnMousePressed(e -> {
// Do stuff
});
}
}
return layout;
});

How to display a colour image using a JPanel?

I have a colour image that is been stored in a 3D array and now I want to display this data or the image on to a JPanel. My code read function is as follows :
public void readImage(String filename) throws Exception {
String filenameExtension = filename.substring(filename.lastIndexOf('.')+1);
File fileImage = FileChosen;
Iterator imageReaders = ImageIO.getImageReadersBySuffix(filenameExtension);
ImageReader imageReader;
if(imageReaders.hasNext())
imageReader = (ImageReader)imageReaders.next();
else
throw new IOException("Unsupported image format");
FileImageInputStream imageInputStream = new FileImageInputStream(fileImage);
imageReader.setInput(imageInputStream);
ImgWidth = imageReader.getWidth(0);
ImgHeight = imageReader.getHeight(0);
BufferedImage bufImage = imageReader.read(0);
imageInputStream.close();
WritableRaster wRaster = bufImage.getRaster();
//int numBands = wRaster.getNumBands();
System.out.println(ImgWidth);
System.out.println(ImgHeight);
imageArray = (new double[ImgHeight][ImgWidth][ColourLevels]);
// get the samples and normalize to between 0 and 1
for(int row = 0; row < ImgHeight; row++)
for(int col = 0; col < ImgWidth; col++)
for(int level = 0; level < ColourLevels; level++)
imageArray[row][col][level] = (wRaster.getSample((col), (row), level) / 255.0);
} // end read method`
Now I want to print the data stored in the imageArray[][][] in to a panel, how can I do that?

Some RGB values seem not to be convertable into a Color Object

I have this kind of method:
public void SaveImageOntoObject(String filepath) throws IOException {
BufferedImage image = ImageIO.read(getClass().getResourceAsStream(filepath));
this.width = image.getWidth();
this.height = image.getHeight();
this.ResetPointInformation();
for (int row = 0; row < width; row++) {
for (int col = 0; col < height; col++) {
this.PointInformation[row][col] = new Color(image.getRGB(col, row));
}
}
}
It takes the filepath of an image as input, converts the RPG Value of each pixel into a Color Object and then stores it into the two-dimensional Array PointInformation of the Object the Method was called onto.
Now to my problem:
While some pictures like this one:
Work like a charm, others like this:
Let me end up with the error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds!
at sun.awt.image.ByteInterleavedRaster.getDataElements(ByteInterleavedRaster.java:318)
at java.awt.image.BufferedImage.getRGB(BufferedImage.java:888)
at Drawing.Object2D.SaveImageOntoObject(Object2D.java:75)** (that's the class whose object's my method works on)
Why is that like that? It seems like Java is not able to convert certain RGB values into Colors?
Could you tell me how I can make it work?
The error message actually says it: "index out of bounds". It seems, that you confused your coordinates and their bounds. getRGB takes the parameters x (range 0 .. width) as first, and y (range 0 .. height) as second.
this.width = image.getWidth();
this.height = image.getHeight();
for (int row = 0; row < height; row++) { // swapped the ...
for (int col = 0; col < width; col++) { // ... bounds
this.PointInformation[row][col] = new Color(image.getRGB(col, row));
}
}
Your first example has width = height, so that the problem doesn't show.

Categories