Detecting multiple images in a single image - java

I need help to identify the border and compare the images with the original image. I need guidance on How can I achieve this through processing or matlab or anything for beginner. for example look at the image below.
Original Image:
The Multiple Image:

The "multiple image" you showed is easy enough to handle using just simple image processing, no need for template matching :)
% read the second image
img2 = imread('http://i.stack.imgur.com/zyHuj.jpg');
img2 = im2double(rgb2gray(img2));
% detect coca-cola logos
bw = im2bw(img2); % Otsu's thresholding
bw = imfill(~bw, 'holes'); % fill holes
stats = regionprops(bw, {'Centroid', 'BoundingBox'}); % connected components
% show centers and bounding boxes of each connected component
centers = vertcat(stats.Centroid);
imshow(img2), hold on
plot(centers(:,1), centers(:,2), 'LineStyle','none', ...
'Marker','x', 'MarkerSize',20, 'Color','r', 'LineWidth',3)
for i=1:numel(stats)
rectangle('Position',stats(i).BoundingBox, ...
'EdgeColor','g', 'LineWidth',3)
end
hold off

You can use correlation method to position the multiple images:
file1='http://i.stack.imgur.com/1KyJA.jpg';
file2='http://i.stack.imgur.com/zyHuj.jpg';
It = imread(file1);
Ii = imread(file2);
It=rgb2gray(It);
Ii=rgb2gray(Ii);
It=double(It); % template
Ii=double(Ii); % image
Ii_mean = conv2(Ii,ones(size(It))./numel(It),'same');
It_mean = mean(It(:));
corr_1 = conv2(Ii,rot90(It-It_mean,2),'same')./numel(It);
corr_2 = Ii_mean.*sum(It(:)-It_mean);
conv_std = sqrt(conv2(Ii.^2,ones(size(It))./numel(It),'same')-Ii_mean.^2);
It_std = std(It(:));
S = (corr_1-corr_2)./(conv_std.*It_std);
imagesc(abs(S))
The result will give you the positions with maximum values:
Get the coordinates of maxima, and position your template centroid at the same position, check the difference between your template and the matching image.
I am not sure what do you mean by "identify the border", but you can always extract the edges with canny detector:
bw=edge(It);
bw=imfill(bw,'holes');
figure,imshow(bw)

Below is presented a solution implemented in Java, using Marvin image processing framework.
Approach:
Load, segment and scale (50x50) the logo in the "original image".
Load, segment and scale (50x50) each logo in the "multiple image"
For each logo in "mulitple image", compare with the logo in "original image". If it is almost the same, draw a rect to highlight.
Comparison method (inside diff plug-in):
For each pixel in two logos, compare each color component. If the difference in one color component is higher then a given threshold, consider that pixel different for the two logos. Compute the total number of different pixels. If two logos have a number of different pixels higher than another threshold, consider them different. IMPORTANT: This approach is very sensitive to rotation and perspective variation.
Since your sample ("multiple image") has only coca logos, I took the liberty to include another logo in order to assert the algorithm.
The Multiple Image 2
Output
In another test, I've included two another similar coca logos. Changing the threshold parameters you can specify whether you want the exact same logo or accept its variations. In the result below, the parameters were set to accept logo variations.
The Multiple Image 3
Output
Source code
public class Logos {
private MarvinImagePlugin threshold = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.color.thresholding");
private MarvinImagePlugin fill = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.fill.boundaryFill");
private MarvinImagePlugin scale = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.transform.scale");
private MarvinImagePlugin diff = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.difference.differenceColor");
public Logos(){
// 1. Load, segment and scale the object to be found
MarvinImage target = segmentTarget();
// 2. Load the image with multiple objects
MarvinImage original = MarvinImageIO.loadImage("./res/logos/logos.jpg");
MarvinImage image = original.clone();
// 3. Segment
threshold.process(image, image);
MarvinImage image2 = new MarvinImage(image.getWidth(), image.getHeight());
fill(image, image2);
MarvinImageIO.saveImage(image2, "./res/logos/logos_fill.jpg");
// 4. Filter segments by its their masses
LinkedHashSet<Integer> objects = filterByMass(image2, 10000);
int[][] rects = getRects(objects, image2, original);
MarvinImage[] subimages = getSubimages(rects, original);
// 5. Compare the target object with each object in the other image
compare(target, subimages, original, rects);
MarvinImageIO.saveImage(original, "./res/logos/logos_out.jpg");
}
private void compare(MarvinImage target, MarvinImage[] subimages, MarvinImage original, int[][] rects){
MarvinAttributes attrOut = new MarvinAttributes();
for(int i=0; i<subimages.length; i++){
diff.setAttribute("comparisonImage", subimages[i]);
diff.setAttribute("colorRange", 30);
diff.process(target, null, attrOut);
if((Integer)attrOut.get("total") < (50*50)*0.6){
original.drawRect(rects[i][0], rects[i][6], rects[i][7], rects[i][8], 6, Color.green);
}
}
}
private MarvinImage segmentTarget(){
MarvinImage original = MarvinImageIO.loadImage("./res/logos/target.jpg");
MarvinImage target = original.clone();
threshold.process(target, target);
MarvinImage image2 = new MarvinImage(target.getWidth(), target.getHeight());
fill(target, image2);
LinkedHashSet<Integer> objects = filterByMass(image2, 10000);
int[][] rects = getRects(objects, image2, target);
MarvinImage[] subimages = getSubimages(rects, original);
return subimages[0];
}
private int[][] getRects(LinkedHashSet<Integer> objects, MarvinImage mask, MarvinImage original){
List<int[]> ret = new ArrayList<int[]>();
for(Integer color:objects){
ret.add(getObjectRect(mask, color));
}
return ret.toArray(new int[0][0]);
}
private MarvinImage[] getSubimages(int[][] rects, MarvinImage original){
List<MarvinImage> ret = new ArrayList<MarvinImage>();
for(int[] r:rects){
ret.add(getSubimage(r, original));
}
return ret.toArray(new MarvinImage[0]);
}
private MarvinImage getSubimage(int rect[], MarvinImage original){
MarvinImage img = original.subimage(rect[0], rect[1], rect[2], rect[3]);
MarvinImage ret = new MarvinImage(50,50);
scale.setAttribute("newWidth", 50);
scale.setAttribute("newHeight", 50);
scale.process(img, ret);
return ret;
}
private void fill(MarvinImage imageIn, MarvinImage imageOut){
boolean found;
int color= 0xFFFF0000;
while(true){
found=false;
Outerloop:
for(int y=0; y<imageIn.getHeight(); y++){
for(int x=0; x<imageIn.getWidth(); x++){
if(imageOut.getIntColor(x,y) == 0 && imageIn.getIntColor(x, y) != 0xFFFFFFFF){
fill.setAttribute("x", x);
fill.setAttribute("y", y);
fill.setAttribute("color", color);
fill.setAttribute("threshold", 120);
fill.process(imageIn, imageOut);
color = newColor(color);
found = true;
break Outerloop;
}
}
}
if(!found){
break;
}
}
}
private LinkedHashSet<Integer> filterByMass(MarvinImage image, int mass){
boolean found;
HashSet<Integer> analysed = new HashSet<Integer>();
LinkedHashSet<Integer> ret = new LinkedHashSet<Integer>();
while(true){
found=false;
outerLoop:
for(int y=0; y<image.getHeight(); y++){
for(int x=0; x<image.getWidth(); x++){
int color = image.getIntColor(x,y);
if(color != 0){
if(!analysed.contains(color)){
if(getMass(image, color) >= mass){
ret.add(color);
}
analysed.add(color);
found = true;
break outerLoop;
}
}
}
}
if(!found){
break;
}
}
return ret;
}
private int getMass(MarvinImage image, int color){
int total=0;
for(int y=0; y<image.getHeight(); y++){
for(int x=0; x<image.getWidth(); x++){
if(image.getIntColor(x, y) == color){
total++;
}
}
}
return total;
}
private int[] getObjectRect(MarvinImage mask, int color){
int x1=-1;
int x2=-1;
int y1=-1;
int y2=-1;
for(int y=0; y<mask.getHeight(); y++){
for(int x=0; x<mask.getWidth(); x++){
if(mask.getIntColor(x, y) == color){
if(x1 == -1 || x < x1){
x1 = x;
}
if(x2 == -1 || x > x2){
x2 = x;
}
if(y1 == -1 || y < y1){
y1 = y;
}
if(y2 == -1 || y > y2){
y2 = y;
}
}
}
}
return new int[]{x1, y1, (x2-x1), (y2-y1)};
}
private int newColor(int color){
int red = (color & 0x00FF0000) >> 16;
int green = (color & 0x0000FF00) >> 8;
int blue = (color & 0x000000FF);
if(red <= green && red <= blue){
red+=5;
}
else if(green <= red && green <= blue){
green+=5;
}
else{
blue+=5;
}
return 0xFF000000 + (red << 16) + (green << 8) + blue;
}
public static void main(String[] args) {
new Logos();
}
}

You can simplify the process proposed by #lennon310 using the normxcorr2 function:
file1='http://i.stack.imgur.com/1KyJA.jpg';
file2='http://i.stack.imgur.com/zyHuj.jpg';
It = imread(file1);
Ii = imread(file2);
It=rgb2gray(It);
Ii=rgb2gray(Ii);
It=double(It); % template
Ii=double(Ii); % image
c=normxcorr2(It, Ii);
imagesc(c);

The simple way (you don't need to write any code) - use Adaptive Vision Studio:
AddLoadImage (and select the image with multiple logos)
Add LocateMultipleObjects_EdgeBased.
Connect outImage from LoadImage to inImage from second filter
Edit inEdgeModel from LocateMultipleObjects_EdgeBased for example my editing result (use Load Image in the plugin to load the Model image ):
Run program and change the parameters of LocateMultipleObjects_EdgeBased to find all elements (i changed inEdgeMagnitude to 9.0 ). You will also get scores for each image:
program with results:
In summary you need to add two filters: loadImage and LocateMultipleObjects_EdgeBased and select the model to find :) It's good for beginner you don't need to write any advanced programs. You can try to solve it also by: detecting circles, TemplateMatching_NCC etc etc...

If you want to detect your object in an environment more complex (rotation, deformation, scaling, perspective), you need a detection method more efficient. I suggest you to see what is called a "cascade classifier for Haar features"
OpenCv can propose you a lot of function to do this method rapidly. See this useful page
Or even by matlab you can see this example

Related

Weird output while processing images with Processing 3.3.7

What I have:
I have 2 images with same size (500), one is a normal image and the other have a message with only black pixels (message) and white pixels (nothing).
What i do in encodeImage() is create messageEncoded with pixels of originalImage and incrementing it by 1 if the pixel of the messageImage isn't white.
This is how i'm hidding a image in another image, so decodeImage() should read the originalImage and messageEncoded to extract the messageImage, creating messageDecoded with white pixel when doens't change the pixel and black and it changes.
PImage originalImage;
PImage messageImage;
PImage messageEncoded;
PImage messageDecoded;
void setup() {
size(500, 500);
originalImage = loadImage("jap.jpg");
messageImage = loadImage("msg.jpg");
messageEncoded = createImage(originalImage.width, originalImage.height, RGB);
messageDecoded = createImage(originalImage.width, originalImage.height, RGB);
encodeImage();
}
void decodeImage() {
originalImage.loadPixels();
messageEncoded.loadPixels();
messageDecoded.loadPixels();
PImage msg = loadImage("messageEncoded.jpg");
msg.loadPixels();
for (int x = 0; x < originalImage.width; x++) {
for (int y = 0; y < originalImage.height; y++ ) {
int loc = x + y * originalImage.width;
if (messageEncoded.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
}
}
messageDecoded.updatePixels();
messageDecoded.save("messageDecoded.jpg");
image(messageDecoded, 0, 0);
}
void encodeImage() {
originalImage.loadPixels();
messageImage.loadPixels();
messageEncoded.loadPixels();
for (int x = 0; x < originalImage.width; x++) {
for (int y = 0; y < originalImage.height; y++ ) {
int loc = x + y * originalImage.width;
if (messageImage.pixels[loc] != color(255)) {
float r = red(originalImage.pixels[loc]);
float g = green(originalImage.pixels[loc]);
float b = blue(originalImage.pixels[loc]);
messageEncoded.pixels[loc] = color(r + 1, g + 1, b + 1);
} else {
messageEncoded.pixels[loc] = originalImage.pixels[loc];
}
}
}
messageEncoded.updatePixels();
messageEncoded.save("messageEncoded.jpg");
//image(messageEncoded, 0, 0);
decodeImage();
}
The Problems:
I have the variable PImage msg in void decodeImage() that I'm not using. This variable should be the same as the global messageEncoded because it's reading the file that it just outputed, but if I use msg, changing
if (messageEncoded.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
into
if (msg.pixels[loc] == originalImage.pixels[loc]) {
messageDecoded.pixels[loc] = color(255);
} else {
messageDecoded.pixels[loc] = color(0);
}
the result is totally different and weird. Why? What is the difference between messageEncoded and msg?
messageDecoded is a little bit wrong, why it's having this wrong black dots?
I made the messageImage in paint, so i though paint is creating non-black dots, but i look all pixels, even put a single black pixel and still appeared some black dots around it.
The originalImage. I found this on google by typing '500x500 images'.
The messageImage. I created this on paint and save it with 500x500 dimentions (for testing it can be and draw with only black and with pixels).
The very weird picture that happens when I use msg. (Problem 1)
The messageDecoded the have black dots around it. Can I call it noise? (Problem 2)
Edit 1:
The weird image and the problem 1 is solved when I use PNG images, but the 2 problem of the "noise" isn't fixed yet
It's likely that JPEG encoding is causing the problem (the noise looks characteristic of compression artifacts). You'll need to work with images in a lossless format such as .PNG to alleviate the problem.
Recreate messageImage, saving it as a .PNG this time.
Convert originalImage to .PNG and modify your code such that
Processing saves the images as .PNG.
It's ok to use a JPEG as the source image; the problem arises from successive JPEG saving/encoding (where more pixels than simply those which are being encoded are changed).

Replace colors in an image without having to iterate through all pixels

Let's say that I have an image like this one (in reality, I have a lot of them, but let's keep it simple)
example picture and I'd like to replace background color (that's the one that's not roads) with green color.
To do that I'd have to iterate through all of the pixels in the map and replace ones that match the color I want to remove.
But as you might think, my image is not a simple as 256x256 picture, but it's slightly bigger, it's 1440p, and the performance drop is significant.
How would I replace all of the unwanted pixels without iterating through all of the pixels.
I'm working with Processing 3 - Java(Android) and I'm currently using this piece of code:
for (x = 0; x < img.width; x++){
for (int y = 0; y < img.height; y++) {
//Color to transparent
int index = x + img.width * y;
if (img.pixels[index] == -1382175 || img.pixels[index] == 14605278 || img.pixels[index] == 16250871) {
img.pixels[index] = color(0, 0, 0, 0);
} else {
img.pixels[index] = color(map(bright, 0, 255, 64, 192));
}
}
}
Solved it with this one:
private PImage swapPixelColor(PImage img, int old, int now) {
old &= ~0x00000000;
now &= ~0x00000000;
img.loadPixels();
int p[] = img.pixels, i = p.length;
while (i-- != 0) if ((p[i]) == old) p[i] = now;
img.updatePixels();
return img;
}
It works like a charm and it takes almost no time:
Swapped colors in 140ms // That's replacing it three times(different colors ofc)

Algorithm to get all pixels between color border?

I have a long png file containing many sprites in a row, but their width/height changes by a little bit. However, all sprites have a fixed blue color 1px border around it.
However, after each sprite, the borders are connected to each other by 2px (just border after border that interacts) see this:
But at the bottom of the sprites, it misses one pixel point
Is there an existing algorithm that can get all pixels between a color border like this, including the border when giving the pixels?
Or any other ideas how to grab all sprites of one file like this and give them a fixed size?
I took your image and transformed it to match your description.
In plain text I went form left to right and identify lines that might indicate a start or end to an image and used a tracker variable to decide which is which.
I approached it like this in Java:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
public class PixelArtSizeFinder {
public static void main(String[] args) throws IOException {
File imageFile = new File("pixel_boat.png");
BufferedImage image = ImageIO.read(imageFile);
int w = image.getWidth();
int h = image.getHeight();
System.out.format("Size: %dx%d%n", w, h);
Raster data = image.getData();
int objectsFound = 0;
int startObjectWidth = 0;
int endObjectWidth = 0;
boolean scanningObject = false;
for (int x = 0; x < w; x++) {
boolean verticalLineContainsOnlyTransparentOrBorder = true;
for (int y = 0; y < h; y++) {
int[] pixel = data.getPixel(x, y, new int[4]);
if (isOther(pixel)) {
verticalLineContainsOnlyTransparentOrBorder = false;
}
}
if (verticalLineContainsOnlyTransparentOrBorder) {
if (scanningObject) {
endObjectWidth = x;
System.out.format("Object %d: %d-%d (%dpx)%n",
objectsFound,
startObjectWidth,
endObjectWidth,
endObjectWidth - startObjectWidth);
} else {
objectsFound++;
startObjectWidth = x;
}
scanningObject ^= true; //toggle
}
}
}
private static boolean isTransparent(int[] pixel) {
return pixel[3] == 0;
}
private static boolean isBorder(int[] pixel) {
return pixel[0] == 0 && pixel[1] == 187 && pixel[2] == 255 && pixel[3] == 255;
}
private static boolean isOther(int[] pixel) {
return !isTransparent(pixel) && !isBorder(pixel);
}
}
and the result was
Size: 171x72
Object 1: 0-27 (27px)
Object 2: 28-56 (28px)
Object 3: 57-85 (28px)
Object 4: 86-113 (27px)
Object 5: 114-142 (28px)
Object 6: 143-170 (27px)
I don't know if any algorithm or function already exists for this but what you can do is :
while the boats are all the same and you wanna get all the pixels between two blue pixels so you can use something like this :
for all i in vertical pixels
for all j in horizontal pixels
if pixel(i,j) == blue then
j = j+ 1
while pixel(i,j) != blue then
you save this pixel in an array for example
j = j+1
end while
end if
end for
end for
This is just an idea and for sure not the most optimal but you can you use it and perform it to make it better ;)

2d Collision Detection - Trying To Get All The Non Transparent Pixels Of Two Sprites

I am in the process of building a 2d game and I am trying to implement pixel level/perfect collision detection.
My problem is I am trying to get all the non transparent pixels of my sprites by using the Buffered Image classes getRGB() method however I can only use this method on Buffered Images.
I was hoping you could point me in the right direction as to what I am trying to do. Below are the methods of my game class I am working in:
This Method Is Supposed To Get All The Non Transparent Pixels In My Sprite
public HashSet<String> getMask(Sprite character){
HashSet <String> mask = new HashSet<String>();
int pixel;
int alpha;
for(int i = 0; i < character.getWidth(); i++){
for(int j = 0; j < character.getHeight(); i++){
pixel = character.getRGB(i,j);
alpah = (pixel >> 24) & 0xff;
if(alpha != 0){
mask.add((character.getX + i) + "," + (character.getY - j));
}
}
}
return mask;
}
Method To Check The Collisions
public boolean checkCollision(Sprite a, Sprite b){
// This method detects to see if the images overlap at all. If they do, collision is possible
int ax1 = a.getX();
int ay1 = a.getY();
int ax2 = ax1 + a.getWidth();
int ay2 = ay1 + a.getHeight();
int bx1 = b.getX();
int by1 = b.getY();
int bx2 = bx1 + b.getWidth();
int by2 = by1 + b.getHeight();
if(by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1){
return false; // Collision is impossible.
}
else {// Collision is possible.
// get the masks for both images
HashSet<String> maskPlayer1 = getMask(shark);
HashSet<String> maskPlayer2 = getMask(torpedo);
maskPlayer1.retainAll(maskPlayer2); // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
if(maskPlayer1.size() > 0){ // if so, than there exists at least one pixel that is the same in both images, thus
System.out.println("Collision" + count);// collision has occurred.
count++;
return true;
}
}
return false;
}
In the getMask() method above you can see that I am saying: character.getRGB() however because character is of type Sprite I am getting an error as I can only use getRGB() with a buffered image.
So as far as I am aware the getRGB() is happy to get the current pixels that the buffered image is moving over in the game but not happy to get the current pixels for a Sprite. I could be misunderstanding how this method works?
So I am wondering if there is any way around this error or if not, would you be able to point me in the right direction
Thanks everyone
Sprite is some class that extends Rectangle or has such properties.
You can add a BufferedImage member to it: whenever you get the RGB from the character you get it from that BufferedImage
int getRGB(int i, int j) {
return myBufferedImage.getRGB(i, j);
}
where you have in Sprite
class Sprite {
BufferedImage myBufferedImage;
public int getRGB(int i, int j) {
......... as shown above
}
....
}

Handling of java.awt.Color while saving file (JPG) with ImageIO.write

Taking part in a Coursera course, I've been trying to use steganography to hide an image in another. This means I've tried to store the "main" picture's RGB values on 6 bits and the "second" picture's values on the last 2 bits.
I'm merging these two values to create a joint picture, and have also coded a class to parse the joint picture, and recover the original images.
Image recovery has not been successful, although it seems (from other examples provided within the course) that the parser is working fine. I suppose that saving the pictures after modification, using ImageIO.write somehow modifies the RGB values I have carefully set in the code. :D
public static BufferedImage mergeImage(BufferedImage original,
BufferedImage message, int hide) {
// hidden is the num of bits on which the second image is hidden
if (original != null) {
int width = original.getWidth();
int height = original.getHeight();
BufferedImage output = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int pix_orig = original.getRGB(i, j);
int pix_msg = message.getRGB(i, j);
int pixel = setpixel(pix_orig, pix_msg, hide);
output.setRGB(i, j, pixel);
}
}
return output;
}
return null;
}
public static int setpixel(int pixel_orig, int pixel_msg, int hide) {
int bits = (int) Math.pow(2, hide);
Color orig = new Color(pixel_orig);
Color msg = new Color(pixel_msg);
int red = ((orig.getRed() / bits) * bits); //+ (msg.getRed() / (256/bits));
if (red % 4 != 0){
counter+=1;
}
int green = ((orig.getGreen() / bits) * bits) + (msg.getGreen() / (256/bits));
int blue = ((orig.getBlue() / bits) * bits) + (msg.getBlue() / (256/bits));
int pixel = new Color(red, green, blue).getRGB();
return pixel;
}
This is the code I use for setting the RGB values of the merged picture. As you can see, I have commented part of the code belonging to red to check whether the main picture can actually be saved on 6 bits, assuming I take int hide=2
Although if I make the same checks in the parsing part of the code:
public static BufferedImage parseImage(BufferedImage input, int hidden){
// hidden is the num of bits on which the second image is hidden
if (input != null){
int width = input.getWidth();
int height = input.getHeight();
BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){
int pixel = input.getRGB(i, j);
pixel = setpixel(pixel,hidden);
output.setRGB(i, j, pixel);
}
}
return output;
}
return null;
}
public static int setpixel(int pixel, int hidden){
int bits = (int) Math.pow(2,hidden);
Color c = new Color(pixel);
if (c.getRed() % 4 != 0){
counter+=1;
}
int red = (c.getRed() - (c.getRed()/bits)*bits)*(256/bits);
int green = (c.getGreen() - (c.getGreen()/bits)*bits)*(256/bits);
int blue = (c.getBlue() - (c.getBlue()/bits)*bits)*(256/bits);
pixel = new Color(red,green,blue).getRGB();
return pixel;
}
I get ~100k pixels where the R value has a remainder if divided by four.
I suspect there' some problem with the function of ImageIO.write.
I know the question is going to be vague, but
1) Can someone confirm this
2) What can I do to get this code working?
Thanks a lot!
JPEG has lossy compression, which means some pixels will effectively be modified when reloading the image. This isn't a fault of ImageIO.write, it's how the format works. If you want to embed your data directly to pixel values, you want to save the image to a lossless format, such as BMP or PNG.

Categories

Resources