How to reduce cached memory?

Hi
If you have an application that processes or creates (using java.awt.Robot) a large number of images (i.e. BufferedImages), the most normal way is to cache them in memory. The question is, how to cache them in the most optimal form?

  • as they are. Namely, directly as BufferedImages?

  • in JPG (or JPEG) format as byte arrays?

  • in PNG format as byte arrays?

Let’s analyze the formats. BufferedImage is a 2-dimensional array of 4 or 3 bytes (ARGB or RGB), JPG is the compression technology of the Joint Photographic Experts Group and PGN is the compression technology of UNISYS. The following codes show you the differences in bytes for the same image Platypus.jpg converted to BufferedImage and PNG format.

import java.io.*;
import java.nio.file.Files;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
// Joe T. Schwarz
public class Test {
  public static void main(String... a) throws Exception {
    if (a.length < 1) {
      System.out.println("Test imagefile");
      System.exit(0);
    }
    byte[] ball = Files.readAllBytes((new File(a[0])).toPath());
    //
    System.out.print("Content in byte["+ball.length+"] of "+a[0]);
    
    //BufferedImage bimg = ImageIO.read(new FileInputStream(a[0]));
    BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(ball));
    int w = bimg.getWidth(), h = bimg.getHeight();
    int rgb[] = bimg.getRGB(0, 0, w, h, null, 0, w);
    //
    ByteArrayOutputStream bao = new ByteArrayOutputStream(0x200000);
    ImageIO.write(bimg, "JPG", bao);
    bao.flush();
    bao.close();
    byte[] jpg = bao.toByteArray();
    
    bao.reset();
    ImageIO.write(bimg, "PNG", bao);
    bao.flush();
    bao.close();
    byte[] pngBuf = bao.toByteArray();
    
    //----------------------------------
    System.out.println(" with Width:"+w+"<>Heigh:"+h);
    System.out.println("RGB["+rgb.length+"] or in byte["+(rgb.length * 4)+"]");
    System.out.println("JPG_buf["+jpg.length+"]<>pngBuf["+pngBuf.length+"]");
  }
}

The output of the Platypus.jpg

java Test platypus.jpg
Content in byte[73683] of platypus.jpg with Width:971<>Heigh:605
RGB[587455] or in byte[2349820]
JPG_buf[73650]<>pngBuf[776006]

If you use an ArrayList to cache the images in their original format as BufferedImages, you will need 2349820 bytes for a Platypus. For the same Platypus, you will need only 73650 bytes in JPG and 776006 bytes in PNG. PNG is larger than JPG, but the difference in quality is so small that you will not notice the difference between JPG and PNG.
The disadvantage of JPG or PNG is that you have to work with the images before you can cache them in ArrayList. But computers are so powerful these days that such a calculation is so fast that there is no noticeable performance problem. An example:

public class BufferedList {
   private List<byte[]> list = new ArrayList<>();
   // add
   public void add(BufferedImage bImg) {
     try {
        ByteArrayOutputStream bao = new
        ByteArrayOutputStream(0x200000);
        ImageIO.write(bImg, "JPG", bao);
        bao.flush();
        bao.close();
        list.add(bao.toByteArray());
    } catch (Exception ex) {
       ex.printStackTrace();
    }
  }
  // get
  public BufferedImage get(int idx) {
    try {
      return ImageIO.read(new ByteArrayInputStream(list.get(idx)));
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return null;
  }
...
}

bác cho em hỏi , giả sử mình có 1 img , sau đó mình chèn 1 watermask vào img đó , thì có cách nào có thể khôi phục img đã bị chèn watermask về nguyên trạng tấm ảnh ban đầu hay không , và cùng câu hỏi cho video

vì em thấy hiện nay , họ nói là xóa watermask nhưng đa phần là chỉnh sửa chứ không phải khôi phục

This depends on the process you are working with. If the image already contains the water mask when you read it, then the water mask is already PART of the image and it is very complicated to remove it. Usually it is like this:

  • If the color of the water mask is uniform, it is relatively easy to replace the water mask with the neighboring RGB that best matches, iterating from begin to end:
// Suppose wrgb is the water mask pixel or RGB
// and the best matching RGB at position x0, y0
for (int y = beginY; y < endY; ++y)
  for (int x = beginX; x < endX; ++x) {
     int rgb = bufferedeImage.getRGB(x0, y0);
     bufferedImage.setRGB(x, y, rgb);
}
  • If you insert the water mask yourself, it is easier to cache it before inserting the water mask. And with an “undo” you just need to restore the backup over the original. Example:
// Suppose you use BufferedList with JPG byte array
BufferedList blist = new BufferedList();
blist.add(my_bufferedImage); // save original
int idx = blist.size() -1; // remember this index
... // create water mask
// restore
my_bufferedImage = blist.get(idx); // restore original
...

vậy tức là bản chất cái hình watermask nó đã ghi đè lên các byte của hình gốc, giờ chỉ khôi phục kiểu làm cho cái hình trông cho giống ảnh gốc, chứ các byte bên trong đã bị thay đổi hoàn toàn ko thể khôi phục à bác

1 Like

Đúng thế, watermask lúc này đã là một thành phần dính liền với hình ảnh. Trừ khi hình đó là hình Photoshop hoặc file PDF đang có nhiều layer và layer chứa watermask nằm riêng thì gỡ bỏ layer đó là xong.

Ngày nay người ta dùng trí tuệ nhân tạo đế cố gắng làm giống nhất chỗ bị chèn watermask nhưng chỉ lừa được con mắt của người dùng tay ngang. Với người chuyên xử lý hình ảnh, làm việc với Photoshop mỗi ngày họ sẽ nhìn ra ngay chỗ đó vừa được “mông má” để cố gỡ bỏ watermask.

Có chuyện này nữa, thay hoàn toán bối cảnh của cái clip bằng một clip giông giống không có watermask, và đây thì việc khó vì rất khó tạo ra clip giống 100% clip gốc, cho nên cách này chỉ dành cho những tay quái kiệt về xử lý ảnh/ video làm biểu diễn 1-2 clip cho vui để thể hiện khả năng con người ăn đứt AI mà thôi.

Vui vui tí, nếu bạn thường xem phim pỏm JAV thì bạn có thể thấy có những clip được “phục hồi” và nếu bạn so nó với bản Uncensored cùng phim đó thì thấy bản gỡ bõ pixelate thực sự là một thảm họa hơn là tạo cả hứng cho người xem, nói đúng hơn bạn sẽ thấy cái đó giống của con trâu hơn là của người :smiley:

Correct! The warter mask is part of the image.

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?