Thursday, October 25, 2007

SharperCV (the .NET wrapper of OpenCV)

This week I had to deal with OpenCV. An old open-source library from Intel which deals with image processing. The "old" means it must be wrapped for usage inside C#, I've found SharperCV does the job and skipped the writing of C++ wrapper.
Next step is compare 2 images.
Welp, it appears that comparing 2 images is not as trivial as you might think, first thing to do is make sure they have the same scale (obvious, but not ensured.) This barrier is non-existent when comparing the image to itself.
After seeing results from the "trivial" comparison I moved on.
The second thing to do is define the comparison method, in the case I was responsible for we chose the easy ones: Xor, optical flow.
Xor is a very good indication as to whether the images are the same or not, low (enough) Xor.sum means the images are identical (too the lowness degree.) Yet even the static frame of "error" has a value larger than 0 for its Xor.
The code for the Xorring:

SharperCV.CvImage CurImage = new SharperCV.CvImage("input1.jpg");
SharperCV.CvImage PrevImage = new SharperCV.CvImage("input2.jpg");
SharperCV.CvImage Xorred = CurImage.Xor(PrevImage, null);
double XorredAlpha = Xorred.Sum().val0;


Optical flow, on the other hand returns a good indication to whether there's a change, but a black frame turning to white frame results in "no change".
A most important thing to do is turn the images to grey, otherwise a nice error message appears.
And the code is:

SharperCV.CvImage greyCurImg = new SharperCV.CvImage(CurImage.Size, SharperCV.BitDepths.IPL_DEPTH_8U, 1);
SharperCV.CvImage greyPrevImg = new SharperCV.CvImage(PrevImage.Size, SharperCV.BitDepths.IPL_DEPTH_8U, 1);
SharperCV.CvImage BMvelx = null;
SharperCV.CvImage BMvely = null;
greyCurImg.CalcOpticalFlowBM(greyPrevImg, blockSize, shiftSize, maxRange, out BMvelx, out BMvely);


I've used the following definitions, but that's cause "it works".
SharperCV.CvSize blockSize = new SharperCV.CvSize(16, 16);
SharperCV.CvSize shiftSize = new SharperCV.CvSize(4, 4);
SharperCV.CvSize maxRange = new SharperCV.CvSize(16, 16);


Be careful, the resulting images are small (we did some "blocking"), but the real value lies in the average, which gives the indication of "change".
Of course fine tuning is required for the results, but that's a must in almost every statistical system.

Thursday, October 18, 2007

Flash - from a programmer's view

As of yesterday I'm a "flash programmer", since it's the first time I've touched flash I had some difficulties. The first is the dev-env, Adobe does (almost) everything to be "not like M$". In some cases it hurts... P.S. if somebody knows what's the keys for the stepping in the debug mode (F10 & F11 in the VS) let me know...

The second thing was an interesting "feature": XML is loaded in the background (async = true), but there's no telling when it finished loading.
The bypass is use a "timer", I used the following code:


//Load the XML
_global.setTimeout(TimeoutFunc,1000,"");

function TimeoutFunc() {
if (my_xml.loaded) {
//The XML was loaded...
} else {
//Check again, you might wish to add a counter for the cases
//Execution must stop and not re-evaluate it every second.
_global.setTimeout(TimeoutFunc,1000,"");
}
}

The strange thing is that a 100ms timeout makes the debugger crash! And with the "feature" of not saving the other files before running them. I swore like sailor on a bad day.

Besides this effect, flash looks like a reasonable scripting enviroment. It's not a real programming heaven, but it's certainly not HELL like VB6. Though a better support for some features would be good.

Thursday, October 11, 2007

Those are the SMILS, I forgot the brackets hiding by the browser...
SMIL1
smil
seq repeatCount="1000"
excl
priorityClass id="Priority1" peers="Stop" lower="Defer"
seq begin="wallclock(2007-10-11T00:00:00)"
media src="PATH_TO_FILE"/
...
/seq>
/priorityClass
/excl
/seq
/smil

SMIL2
smil
seq repeatCount="1000"
excl
priorityClass id="Priority1" peers="Stop" lower="Defer"
seq begin="wallclock(2007-10-11T00:00:00)"
media src="PATH_TO_FILE"/
...
/seq>
/priorityClass
priorityClass id="Priority2" peers="Stop" lower="Defer"
seq
media src="PATH_TO_FILLER"/
...
/seq>
/priorityClass
/excl
/seq
/smil
This is my BLOG's initial post:)

I'll deal today with one of the most annoying tasks: converting a bunch of excel shits (sheets is not the correct term for excel) to a SMIL.

First thing to do is "standardize the format", excel is a large grid (2D array) while the SMIL is an hierarchical XML. This means that a certain column(s) in the excel transforms to a certain value in the SMIL.

In this case I used the sheets name as the date, column A as the hour, and column B as the file to play. The resulting SMIL should be of this format:






...





The excel code (for creating the sequences) is:

i=2
while range("A1").cells(i,2).text<>""
if range("A1").cells(i,1).text<>"" then
res = res & ""
res = res & ""
end if
res = res & "
wend
res = mid(res, 7) 'Remove the first "
"

NOTE:
The SMIL format presented earlier might appear to hang at times. This is due to the fact no "fillers" were supplied. Usually where I work we solve it by using a SMIL of this type:






...





...






In this case when the priority1 items stop to play the priority2 item continues it's play. The priority1 items enter when the relevant event is fired (in the SMILs in this post it's an exact time)