跳到主要內容

A Java De-flicker Class based on Donald Graft's idea

Since QuickTime for Java has been depreciated in year 2009, and JMF (Java Media Framework) has to call for external library, there is a need to search alternative way assembling Jpeg images into a QuickTime movie.  I know Time Lapse Assembler has done a excellent job at this under Mac OS X, and it is free.  But Time Lapse Assembler fails to deal with the flickering problem commonly seen in Time-Lapse videos.  As a result, I have to find a pure-java way to write QuickTime file, and to deal with the flickering problem under Mac OS X.

Werner Randelshofer's Blog has a good solution writing QuickTime movies.  All I need to do myself is de-flickering.  Again, open-source resources help a lot.  Donald Graft kindly provides his source code of Deflicker Filter for VirtualDub.  We can learn his algorithm from the code. Graft's deflicker was written in C++.  However, what I need is Java.  So I re-write part of Graft's deflicker.  (Sorry, I still have no idea about the soften phase….)

The basic idea is simply.  As Graft wrote inside his code, "The adjustment factor is determined from a moving average of the luminance's of the past frames in the window."  Thus, what I need to do is quite simple, calculating the luminance (sum of each pixel's r+g+b divided by width*height*3) of each frame.  And then, just following Graft's idea.  Here is my deflicker filter code.



package org.sustudio.deflicker;

import java.awt.image.BufferedImage;

public class DonaldGraftDeflicker {

	private int window;
	private int scene_change_threshold;
	private int lumnData[];
	
	public DonaldGraftDeflicker(int window, int threshold) {
		this.window = window;
		this.scene_change_threshold = threshold;
		this.lumnData = new int[window];
		
		// first frame infication.
		this.lumnData[0] = 256;
	}	
			
	public BufferedImage deflicker(BufferedImage img) {
		BufferedImage image = img;
		int w = image.getWidth();
		int h = image.getHeight();
		int lum_sum = 0;
		
		// Calculate the luminance of the current frame.
		for (int y=0; y> 16) & 0xff;
				int green = (pixel >> 8) & 0xff;
				int blue = (pixel >> 0) & 0xff;
				//lum_sum += red + green + blue;
				
				lum_sum += (int) Math.ceil((0.299 * red) + (0.587 * green) + (0.114 * blue));
			}
		}
		//lum_sum /= (w * h * 3.0);
		lum_sum /= (w * h);
		System.out.print(lum_sum + "\t");
		
		// Do scene change processing.
		//boolean scene_change = false;
		if (this.scene_change_threshold < 256 &&
			this.lumnData[0] != 256 &&
			Math.abs((int)lum_sum - (int)this.lumnData[window-1]) >= this.scene_change_threshold)
		{
			this.lumnData[0] = 256;
			//scene_change = true;
		}
		
		
		// Calculate the adjustment factor for the current frame.
		// The adjustment factor is determined from a moving average
		// of the luminances of the past frames in the window.
		double scale = 1.0;
		if (this.lumnData[0] > 255) {
			for (int i=0; i 0) {
				scale = 1.0 / (double) lum_sum;
				double filt = 0.0;
				for (int i=0; i> 16) & 0xff;
				int green = (pixel >> 8) & 0xff;
				int blue = (pixel >> 0) & 0xff;
				int max = Math.max(Math.max(red, blue), green); 
				if (scale * max > 255.0) scale = 255.0 / (double)max;
				red = (int) (scale * red);
				green = (int) (scale * green);
				blue = (int) (scale * blue);
				pixel = (red & 0xff) << 16 | (green & 0xff) << 8 | (blue & 0xff) << 0;
				image.setRGB(x, y, pixel);
				lum_sum += (int) Math.ceil((0.299 * red) + (0.587 * green) + (0.114 * blue));
			}
		}
		lum_sum /= (w * h);
		System.out.println(lum_sum);
		
		return image;
		
	}
		
	private int getPixelGrayValue(int rgb) {
		int red = (rgb >> 16) & 0xff;
		int green = (rgb >> 8) & 0xff;
		int blue = (rgb >> 0) & 0xff;
		
		//return (int) Math.ceil((0.2126 * red) + (0.7152 * green) + (0.0722 * blue));
		return (int) Math.ceil((0.299 * red) + (0.587 * green) + (0.114 * blue));
	}
	
}

留言

熱門文章

差不多食譜:萬聖節的蛋白霜幽靈們 Halloween Meringue Ghosts

說到十月,月底的萬聖節肯定是驚嚇指數最高的一天,到處飄忽的幽靈們更是西洋鬼節的主角。不甘心這天總是被 Trick-or-Treat(不給糖就搗蛋)威脅,差不多食譜今年要開始來反擊,邀請大家來當 Ghostbusters 魔鬼剋星,將這群調皮搗蛋的幽靈們一網打盡。 抓鬼的先決條件就是⋯⋯得有些幽靈鬼怪來抓。這可是練習擠花的好時機,因為幽靈本來就是奇形怪狀的,什麼樣的怪樣子都不奇怪,太精緻反而有點奇怪呢!做好直送嘴巴「喀嚓」,看它還敢不敢來 Trick-or-Treat!

差不多食譜:蜂蜜烤南瓜 Roasted Pumpkin with Honey

還記得差不多食譜分享過用煎的南瓜吧!那是屬於家常菜的做法,現在差不多食譜推出另外一種做法,淋上蜂蜜,用烤箱加上精緻的裝飾,讓家常菜變身成為派對食物。相信當你端出這盤「蜂蜜烤南瓜」時,肯定會吸引不少眼球的注意。

金門。毋忘在莒勒石 “Wu Wang Zai Jyu” Inscription

金門有塊石頭,不去看看感覺怪怪的,看了又覺得實在沒什麼。聰明的你應該猜到了,就是那塊出現在教科書裡頭的「毋忘在莒」,金門的象徵。印象中,刻著「毋忘在莒」的那塊大石頭旁邊光禿禿的。或許從小學畢業二十多年後,我頭一次有機會來拜見這塊石頭,旁的小樹苗已經長成這副模樣了吧!再過幾年,恐怕要在林蔭中尋找「毋忘在莒」這四個字。但真要問起「毋忘在莒」這四個字是什麼意思,我相信不少人需要稍微想一下。