java bufferedimage数组数据立即改变

java bufferedimage array data immediately changes

    import javax.imageio.ImageIO;

    import org.bytedeco.javacv.FFmpegFrameGrabber;

    public class FrameData 
    {   
int count = 0;
int picWidth;
int picHeight;

BufferedImage img = null;

//GET FRAME COUNT
public int gf_count(int numofFrames, BufferedImage[] frameArray, String fileLocationsent, String videoNamesent) throws IOException
{        
    String fileLocation = fileLocationsent;
    String videoName = videoNamesent;

    int frameNums = numofFrames;
    int totFrames = 0;

            FFmpegFrameGrabber grab = new FFmpegFrameGrabber(fileLocation + videoName);

        try {   grab.start(); } 
        catch (Exception e) {   System.out.println("Unable to grab frames");  }

                    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  
                File outputfile = new File(fileLocation + "GrayScaledImage" + i + ".jpg");
                ImageIO.write(frameArray[i], "jpg", outputfile);
            } 
            catch (Exception e) {   /*e.printStackTrace();*/    }
        }//END for

                return totFrames;

    }//END METHOD long getFrameCount()

希望有人能给我解释一下... 我正在学习 java 所以这里... 我编写这段代码来计算 .mov 文件中的帧数并测试我生成的图像文件的缓冲图像数组。正如代码一样,它按计划工作......问题是在捕获之后立即出现,如果我将缓冲图像作为文件发送出去,它们似乎都只是第一张图像。请参阅下面的示例...

    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  
                File outputfile = new File(fileLocation + "GrayScaledImage" + i + ".jpg");
                ImageIO.write(frameArray[i], "jpg", outputfile);
            } 
            catch (Exception e) {   /*e.printStackTrace();*/    }
        }//END for

现在如果我将其更改为...

    for(int i = 0 ; i < frameNums  ; i++) 
        {
            try 
            {                   
                frameArray[i]= grab.grab().getBufferedImage();
                totFrames = i;  catch (Exception e) {   /*e.printStackTrace();*/    }}
    for(int j = 0; j < frameNums; j++)
    {
    File outputfile = new File(fileLocation + "GrayScaledImage" + j + ".jpg");
                ImageIO.write(frameArray[j], "jpg", outputfile);
    }

我不明白为什么我会反复收到相同的图像。 如果需要进一步的信息,请让我知道,这是我的第一个在线编程问题......通常会找到别人问过的我正在寻找的东西。找不到这个。 谢谢你的时间 肯

问题是 grab().getBufferedImage() 每次都在同一个缓冲区中工作。当您在循环中分配对该缓冲区的引用时,您是在分配对同一缓冲区 numofFrames 次的引用。那么你写的不是第一帧,而是最后一帧。为了解决这个问题,您需要对 BufferedImage 执行 "deep copy"。请参阅下面的代码:

public class FrameData {
    BufferedImage img;
    Graphics2D g2; 
    // GET FRAME COUNT
    public int gf_count(int numFrames, BufferedImage[] frameArray, String fileLocation, String videoName) throws Exception, IOException {
        Java2DFrameConverter converter = new Java2DFrameConverter();
        int totFrames = 0;

        img = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB);
        g2 = img.createGraphics();

        FFmpegFrameGrabber grab = new FFmpegFrameGrabber(fileLocation + videoName);
        grab.start();
        for (int i = 0; i < numFrames; i++) {
            frameArray[i] = deepCopy(converter.convert(grab.grab()));
            totFrames = i;
        }
        for (int j = 0; j < totFrames; j++) {
            File outputfile = new File(fileLocation + "TImage" + j + ".jpg");
            ImageIO.write(frameArray[j], "jpg", outputfile);
        }
        return totFrames;
    }// END METHOD long getFrameCount()

    BufferedImage deepCopy(BufferedImage bi) {
        ColorModel cm = bi.getColorModel();
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = bi.copyData(null);
        return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }
    // This does what the converter.convert seems to do, which
    // is decode an image into the same place over and over.
    // if you don't copy the result every time, then you end up
    // with an array of references to the same last frame.
    BufferedImage draw() {
        g2.setColor(new Color(-1));
        g2.fillRect(0, 0, 100, 50);
        g2.setColor(new Color(0));
        g2.drawLine(0, 0, (int)(Math.random()*100.0), (int)(Math.random()*50.0));        
        return img;
    }

    public static void main(String... args) throws Exception, IOException {
        new FrameData().run();        
    }
    private void run() throws Exception, IOException {
        BufferedImage images[] = new BufferedImage[50];
        gf_count(50, images, "C:/Users/karl/Videos/", "dance.mpg");
    }
}

我已经包含了一个 draw() 方法,它通过示例展示了如何在同一个 BufferedImage 中重复完成工作,以防您想重现该问题。

当然还有其他方法可以进行深拷贝,并且显示的方法可能存在问题。参考:How do you clone a BufferedImage.

PS> 我更新了代码以使用 bytedeco 库的 1.1 版本。