# Main # Dev # Apps #

CSRBappNotHotdog

CSRBappNotHotdog is a demo application to demonstrate the client/provider Service Oriented operation of a CSRB based distributed application. It facilitates two types of CSRB users, a Service Client and a Service Provider.

The Service Provider consists of an image classifier application that using an already trained model it can process images taken by other CSRB users and identify if the image is or not a photo of a hotdog. The application receives a CSRB message that contains information about where the image to be process is stored (within the CSRB network), retrieves the image, and passes it through the image recognition classifier. The result is returned back to the CSRBnode that requested the activity.

The Service Client consists of an Android application, running a CSRBnode, which takes a photo, stores it within the local CSRBnode's CSRBobject database, and sends a message to the Service Provide to request the image recognition activity. The application displays the outcome when it arrives. In the meantime, the local CSRBnode is serves to the remote Service Provider the Objects that contain the image data, when requested.

Demonstration Key Points

  • Smart-phone is a low-spec Nexus 5.
  • Full resolution photos taken and transferred (~4MB each).
  • Smart-phone connected to the internet over 4G connection and located indoors.
  • Demonstration recorded in real time.

Demonstration Network Points

  1. CSRBnode #1 / CSRBapp Test Android Application (Nexus5, 4G)
  2. CSRBrouter #1 (Azure free-tier VM, Standard B1ls, 1 vcpus, 0.5 GiB memory, London region)
  3. CSRBrouter #2 (Wired Internet 200Mb/20Mb, oDroid-C2 SBC)
  4. CSRBnode #2 / Python TensorFlow application (Gbit LAN, desktop computer i7-4790K)

Demonstration Video

Communication Flow

Application code CSRB specific components

This is the CSRB specific code integrated into the Android application, to show the level of CSRB integration complexity.

NOTE: This is a basic functional code without complete and thorough error checking & handling.

Copy the local image file to the local CSRBnode's CSRBdb

Read the contents of the local image file and store them in the local CSRBdb storage as a block of objects, using the CSRBvfs subsystem. A random address/identifier is set as a unique location id of the objects used.

/* generate a random ObjectID, to use as the base ID for the stored image file objects */
Random r = new Random();
byte[] rn = new byte[16];
r.nextBytes(rn);
objectID = new BigInteger(rn);


Bundle b;
b = new Bundle();

/* set which file to copy to the local CSRBdb */
b.putString("FILENAME", currentPhotoPath);
/* "currentPhotoPath" is the full path of the local file that we passed to the
   Android Image Capture activity */

/* confirm the size of the file */
b.putLong("FILESIZE", photoFile.length());
/* "photoFile" is the local file object passed to the Android Image Capture activity */

/* set the generated ObjectID as the location base ID where the file objects will be stored */
b.putByteArray("OBJECTID", objectID.toByteArray());

/* request from the Android CSRBapp Service to copy the file to the local CSRBdb */
MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_OBJECT_SET_FROM_FILE, b);

Request the Image Recognition activity from the Service Provider CSRBnode

Information about the Service Client and the location ID of the stored photo date are sent via a CSRB Message to the remote Image Recognition CSRBnode user service.

/* generate a random file handle for the CSRB Channel backend access */
rn = new byte[8];
r.nextBytes(rn);
processorResultHandle = new BigInteger(rn);

/* generate a random CSRB Channel ID to be used as the address where the image
   recognition results are sent from the Service Provider CSRBnode */
rn = new byte[8];
r.nextBytes(rn);
processorResultChannel = new BigInteger(rn);

b = new Bundle();
b.putByteArray("HANDLE", processorResultHandle.toByteArray());
b.putByteArray("CHANNELID", processorResultChannel.toByteArray());
/* request from the Android CSRBapp Service to open a CSRB Channel, to be able
   to receive the result Message */
MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_CHANNEL_OPEN, b);

/* set the destination NodeID and Channel ID of the Service Provide, where the
   request for the Image Recognition activity will be sent */
/* NOTE: these have been statically set for this demo */
processorNodeID = new BigInteger("384D12EE2BAC85DA4AA9145E48742B42", 16);
processorChannel = new BigInteger("5EF25423F787C644", 16);

/* assemble the CSRB Message to be sent */
CSRBprotocolMessage msg = new CSRBprotocolMessage();
msg.setParams(0, new BigInteger(new byte[16]), processorResultChannel);
msg.setParams(1, objectID, BigInteger.valueOf(photoFile.length()));
b = new Bundle();
b.putByteArray("DESTINATIONNODEID", processorNodeID.toByteArray());
b.putByteArray("DESTINATIONCHANNEL", processorChannel.toByteArray());
b.putByteArray("MESSAGE", msg.toByteArray());

/* send CSRB Message to the Service Provider */
MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_MESSAGE_SEND, b);

Image Recognition application

The Python Image recognition program processes activity requests Messages from any remote CSRBnode.
The image is accessed directly from the remote CSRBnode as a virtual local file. The whole transfer process is handled transparently by the local CSRBnode running in FUSE VFS mode, using the Object information included in the received Message.

# vim: set ts=8 sts=8 sw=8 tw=0 noet:

from CSRBfuseAPI import *
import time
#from PIL import Image
import os

# import the "hotdog-or-not-hotdog" classifier
# NOTE: this is based on on https://github.com/VPanjeta/hotdog-or-not-hotdog,
# modified to run with OpenCV2 and as a function
import sys
sys.path.append("hotdog-or-not-hotdog/")
from label_dog import *

# open the local CSRB Channel to receive activity execution requests from remote CSRBnodes
h = CSRBmessageOpen("/mnt/CSRB/MESSAGE/00000000000000000000000000000000/5EF25423F787C644");

while True:
        print("Waiting for message")

        while True:
                m = CSRBmessageReceive(h);
                if m != None:
                        break
                #print("EMPTY")
                time.sleep(0.1)

        print("Received message: " + str(m))

        # calculate the number of Objects used to store the image file
        fileBlocks = math.ceil(m.header.params[1].num / 1024)

        # open the block of Objects from the REMOTE CSRBnode's CSRBdb, as a virtual local file
        localFile = "/mnt/CSRB/OBJECTBLOCK/" + \
                str(m.header.params[0].id) + "/" + \
                str(m.header.params[1].id) + m.header.params[1].numHexBlocks(1024)

        print("File: " + localFile)

        print("FileSize: " + str(m.header.params[1].num))
        print("FileBlocks: " + str(fileBlocks))

        # pass the local file to the image classifier
        try:
                r = label_dog(localFile)
                print(r)
        except:
                print("IMAGE DETECTION FAILED")
                r = [0, 0]

        #im = Image.open(localFile)
        #im.show()
        #os.system("qiv " + localFile + " &")

        # open a CSRB Channel to the remote CSRBnode's address and Channel ID
        rh = CSRBmessageOpen("/mnt/CSRB/MESSAGE/" +
                str(m.header.params[0].id) + "/" +
                format(m.header.params[0].num, '0>16X'))
        if rh == None:
                continue

        # assemble a simple Message with the image recognition result
        rm = CSRBprotocolMessage()
        rm.header.params[0].num = r[1]

        # send the Message to the CSRBnode that requested the activity
        CSRBmessageSend(rh, rm)

        # clean-up
        CSRBmessageClose(rh)

        # rinse, repeat

# cleanup
CSRBmessageClose(h)

Receive and displays image recognition result

The Android activity polls the CSRBbackend to check for the reception of the image recognition result Message. The result is then displayed and the CSRB Channel operation is terminated.

...
/* register a callback to handle received messages */
MainActivity.csrbBackend.registerMessageReceiveCallback(messageReceiveCallback);
...
/* create a poller for received CSRB Messages */
refreshHandler = new Handler();
refreshRunnable = new Runnable() {
	@Override
	public void run() {
	messagesFetch();
	refreshHandler.postDelayed(refreshRunnable, 503);
}
};
...

synchronized private void messagesFetch() {
	if(processorResultHandle == null) {
		return;
	}

	/* request from the Android CSRBbackend service to send back
	   any received CSRB messages from the CSRB Channel */
	Bundle data = new Bundle();
	data.putByteArray("HANDLE", processorResultHandle.toByteArray());
	data.putByteArray("CHANNELID", processorResultChannel.toByteArray());
	MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_MESSAGE_RETRIEVE_REQUEST, data);
}

CSRBappBackend.messageReceiveInterface messageReceiveCallback = new CSRBappBackend.messageReceiveInterface()
{
	@Override
	public boolean handleMessage(int type, Bundle data)
	{
		switch (type) {
			case CSRBappService.MSG_MESSAGE_RETRIEVE_RESPONSE:
				CSRBprotocolMessage message = new CSRBprotocolMessage();

				/* retrieve the CSRB message data from the Android message */
				byte[] m = data.getByteArray("MESSAGE");

				if(m.length == 0) return true;

				message.fromByteArray(m);

				byte[] o = new byte[16];
				byte[] n = new byte[8];

				/* retrieve the message parameter that holds the result */
				message.getParams(0, o, n);
				byte result = n[0];

				/* do a simple image overlay to show the result */
				if(result == 1) {
				    ivNotHotdogResultOverlay.setImageResource(R.drawable.ic_checkmark);
				} else {
				    ivNotHotdogResultOverlay.setImageResource(R.drawable.ic_fail);
				}

				/* clean-up the temp file, close the Channel, etc */
				cleanup();

				return true;
			default:
				break;
		}
		return false;
	}
};

private void cleanup() {
	/* stop polling for received Messages */
	refreshHandler.removeCallbacks(refreshRunnable);

	/* request from the Android CSRBbackend to delete the CSRBdb objects used to store the image file */
	if (objectID != null) {
		Bundle b;
		b = new Bundle();
		b.putByteArray("DESTINATIONNODEID", new byte[16]);
		b.putByteArray("OBJECTSBASE", objectID.toByteArray());
		b.putLong("FILESIZE", photoFile.length());
		MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_OBJECT_DEL_REQUEST, b);
		objectID = null;
	}

	if (currentPhotoPath != null) {
		currentPhotoPath = null;
	}

	/* delete the local photo file */
	if (photoFile != null) {
		photoFile.delete();
		photoFile = null;
	}

	/* close the CSRB Channel */
	if (processorResultHandle != null) {
		Bundle data = new Bundle();
		data.putByteArray("HANDLE", processorResultHandle.toByteArray());
		data.putByteArray("CHANNELID", processorResultChannel.toByteArray());
		MainActivity.csrbBackend.serviceMessageSend(CSRBappService.MSG_CHANNEL_CLOSE, data);

		processorResultHandle = null;
		processorResultChannel = null;
	}
}

# Email # Twitter # IRC # © 2017-2021 SRDI/CSRB #