跳到主要內容

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));
	}
	
}

留言

熱門文章

差不多食譜:牡丹魚片 Fish Slices Moutan

往餐桌端上這一道「牡丹魚片」,需要解釋的大概只有「這真的是我做的!」它是道不折不扣的大菜,能把一塊平凡無奇的魚片,展開變成一朵朵牡丹花。做這道菜最需要的不是技巧,是耐心;當然還有一點美學的天份!

【跟著我的閱讀腳步】山居歲月:普羅旺斯的一年 A Year in Provence

就記得我看過Peter Mayle(彼得.梅爾)的作品,而且對他在第一章大談用塑膠湯匙吃高級魚子醬的說法印象深刻,但怎麼樣就是想不起來到底是哪一本書。好在有些現代科技的幫忙,找出了那本令我印象深刻的《 關於品味 》。只不過,在《 關於品味 》之前,Peter Mayle還有另一部更加出名的作品——《 山居歲月:普羅旺斯的一年 》( A Year in Provence )。 穿襪子這件事已成遙遠的記憶,手錶躺在抽屜裡也已很久了。我發覺,憑著庭院中樹影的位置,我可以大致估算出時間;至於今日何日,我就不大記得了。反正也不重要。我快要化為安份守己,無欲無求的院中蔬菜了;與現實世界的偶然接觸,僅限於在電話中與遠方辦公室裡的人交談。他們總是欣羨渴慕地問起天氣如何,答案則讓他們鬱鬱不樂。他們寬慰自己的方法是警告我會得皮膚癌,又說太陽曬多了頭腦會遲鈍。我並不與他們爭執;他們也許說的沒錯。只不過,變笨也好,增添皺紋也好,可能得癌症也罷,我從來沒像現在這麼快活過。 ---《 山居歲月 》, pp. 173-174

「抓烏龜」的麻將遊戲

今天要和大家分享一個打發時間的簡單遊戲——抓烏龜。這可是我老爸老媽特別從美國學回來的,是個名符其實的「海歸」遊戲,據說是在下雪時無聊打發時間用的。