Friday, May 11, 2007

Programming MSMQ (Microsoft Message Queue) - Sample code

Yesterday, I went to "MSDN Connection Training Sneak Peak Preview" seminar at Microsoft Thailand. The topic is "Distributed Application Development with Visual Studio 2005". It is actually a shortened version of Iverson training course : if you want to take a full course, you will have to pay at least ten thousand baht for 3 days training o__O!

I really learned many things from this session. One of them is MSMQ or Microsoft Message Queue.

Message queuing is a communication tool that allows applications to reliably interconnect in a distributed environment where one of the applications may or may not be available at any given time. The queue acts as a holding container for messages as they are sent between applications. The applications send messages to and read messages from queues to communicate back and forth. An application writes a message to a queue, which will then be received and processed by another application at some point determined by the receiving application. This type of communication is designed for asynchronous use where the applications involved are not waiting for an immediate response from the other end. - http://www.codeguru.com/Csharp/.NET/net_general/netframeworkclasses/article.php/c4241/


This really fits into my project's need for a queue which can serve clients over the internet.

To program the MSMQ you need to install Messaging Queuing first. Insert your Windows Setup CD and choose "Install optional Windows components". Then, tick the checkbox in front of "Message Queuing" and go on.



Now, create a new Visual C# Console project. Add reference to System.Messaging and add the following code.




using System;
using System.Collections.Generic;
using System.Text;
using System.Messaging;
using System.Threading;

namespace MSMQSample
{
class Program
{
static void Main(string[] args)
{
// Check if queue alreasy exists.
string queuePath = @".\private$\SampleQueue";
MessageQueue queue;
if (!MessageQueue.Exists(queuePath))
// If not, create one.
queue = MessageQueue.Create(queuePath);
else
queue = new MessageQueue(queuePath);

// Send something to queue.
DateTime dt = DateTime.Now;
Console.WriteLine("Message to send: " + dt.ToString());
Message sendMsg = new Message(dt, new XmlMessageFormatter());
queue.Send(sendMsg, "My DateTime");

// Wait for five seconds.
Thread.Sleep(5000);

// Get sent message from queue.
Message receiveMsg = queue.Receive();
receiveMsg.Formatter = new XmlMessageFormatter(
new Type[] { typeof(DateTime) });
DateTime ret = (DateTime)receiveMsg.Body;

Console.WriteLine("Message Received: " + ret);
Console.Read();


}
}
}


And this is what our message looks like. You can open this window in Computer Managment/Services and Applications/Message Queuing/samplequeue



Here are some great resources on the basics of MSMQ:
And for those who want to attend next MSDN Connection Training Sneak Peak Preview you have to register for an account at http://www.msdnconnection.com/thailand and monitor this page [MSDN Connection Training Sneak Peak Preview]



Wednesday, May 2, 2007

Really simple blob detector

Few days ago while i was reading news at Blognone, I spotted an interesting topic on how to detect
(and calculate the area of ..) circles in an image. This is a well-known problem in the field of Computer Vision known as Blob Detection. I had some experiences in implementing the blob detector in C and C# but had never done it in Java. So I decided to write one. The code was more compact and straight to the point than my C and C# version.

This is the input image.



And here is my code.




package blobdetector;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import javax.imageio.ImageIO;
import javax.management.Query;

/**
*
* @author m3rlinezatgmaildotcom
*/
public class Main {

public Main() {
}

public static boolean isBlack(BufferedImage image,int posX,int posY){
// หาสีที่สุดที่สนใจ
int color = image.getRGB(posX,posY);

// หาค่าความสว่างจากการเฉลี่ย RGB
int brightness =
(color & 0xFF) +
((color >> 2) & 0xFF) +
((color >> 4) & 0xFF);
brightness /= 3;
return brightness < 128;
}

public static void main(String[] args) {
if(args.length != 1){
System.err.println("ERROR: Pass filename as argument.");
return;
}

String filename = args[0];
// String filename = "C:\\Users\\Natthawut\\Desktop\\Polymorphism\\blob.jpg";
try {
BufferedImage bimg = ImageIO.read(new File(filename));

// map สำหรับเก็บว่าจุดใดบ้างที่ได้รับการสำรวจไปแล้ว
boolean[][] painted =
new boolean[bimg.getHeight()][bimg.getWidth()];

// วนรอบทุกจุดในรูป
for(int i = 0 ; i < bimg.getHeight() ; i++){
for(int j = 0 ; j < bimg.getWidth() ; j++) {
// System.out.println(i + " " + j + " b " + isBlack(bimg,j,i));
// ถ้าจุดนั้นเป็นสีดำ และยังไม่เคยถูกสำรวจ
if(isBlack(bimg,j,i) && !painted[i][j]){

// ทำการ floodfill
Queue<Point> queue = new LinkedList<Point>();
queue.add(new Point(j,i));

int pixelCount = 0;
while(!queue.isEmpty()){
Point p = queue.remove();

// เช็คว่าจุดที่ดึงมาอยู่ในขอบเขต
if((p.x >= 0) && (p.x < bimg.getWidth() && (p.y >= 0) && (p.y < bimg.getHeight()))){
if(!painted[p.y][p.x] && isBlack(bimg,p.x,p.y)){
painted[p.y][p.x] = true;
pixelCount++;

// ใส่จุดรอบๆจุดที่ดึงออกมาลงไปในคิว
queue.add(new Point(p.x + 1,p.y)); queue.add(new Point(p.x - 1,p.y));
queue.add(new Point(p.x,p.y + 1)); queue.add(new Point(p.x,p.y - 1));
}
}
}
System.out.println("Blob detected : " + pixelCount + " pixels");
}

}
}

} catch (IOException ex) {
ex.printStackTrace();
}

}

}




And here is the output.

Blob detected : 1 pixels
Blob detected : 1339 pixels
Blob detected : 1 pixels
Blob detected : 5582 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 4018 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels
Blob detected : 1 pixels


Edit: P'Deans4J suggested me to write the same program using recursion too. Here is my code in recursive version. I added another static method "floodfill" which returns number of pixels in current blob.




package blobdetector;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import javax.imageio.ImageIO;
import javax.management.Query;

/**
*
* @author m3rlinezatgmaildotcom
*/
public class Main {

public Main() {
}

public static boolean isBlack(BufferedImage image,int posX,int posY){
// หาสีที่สุดที่สนใจ
int color = image.getRGB(posX,posY);

// หาค่าความสว่างจากการเฉลี่ย RGB
int brightness =
(color & 0xFF) +
((color >> 2) & 0xFF) +
((color >> 4) & 0xFF);
brightness /= 3;
return brightness < 128;
}

public static int floodfill(
BufferedImage image,
boolean[][] painted,
int posX, int posY){

// ตรวจสอบขอบเขต
if((posX < 0) || (posX >= image.getWidth()) || (posY < 0) || (posY >= image.getHeight()))
return 0;

if(!painted[posY][posX] && isBlack(image,posX,posY)){
painted[posY][posX] = true;
return 1 + floodfill(image,painted,posX+1,posY) +
floodfill(image,painted,posX-1,posY) +
floodfill(image,painted,posX,posY+1) +
floodfill(image,painted,posX,posY-1);
}

return 0;
}

public static void main(String[] args) {
if(args.length != 1){
System.err.println("ERROR: Pass filename as argument.");
return;
}

String filename = args[0];

try {
BufferedImage bimg = ImageIO.read(new File(filename));

// map สำหรับเก็บว่าจุดใดบ้างที่ได้รับการสำรวจไปแล้ว
boolean[][] painted =
new boolean[bimg.getHeight()][bimg.getWidth()];


// วนรอบทุกจุดในรูป
for(int i = 0 ; i < bimg.getHeight() ; i++){
for(int j = 0 ; j < bimg.getWidth() ; j++) {

// ถ้าจุดนั้นเป็นสีดำ และยังไม่เคยถูกสำรวจ
if(isBlack(bimg,j,i) && !painted[i][j]){

int pixelCount = floodfill(bimg,painted,j,i);

System.out.println("Blob detected : " + pixelCount + " pixels");
}

}
}

} catch (IOException ex) {
ex.printStackTrace();
}

}

}


While the recursive version uses less LOC, easier to understand and easier to code than the first solution, its performance is not as good as the first one and it actually gives me java.lang.StackOverflowError when used with the sample image. But if the problem's size is small, I prefer implementing the recursive version too.