Codeine .Net RSS 2.0
# Monday, 09 July 2012

I have been doing a bit of work lately analyzing images from both video streams and static pictures and apparently I have found the process interesting enough to write about it. It's not very often that I can get away from the standard CRUD type application and I really found it interesting to dig into the basics of image analysis.

For the tasks I have been working on I've needed to get down to the individual pixels of an image. There are various ways to do this, some of them possibly easier than what I am going to be walking through, but due to the circumstances of what I needed to do this was then best method for me to accomplish it.

 

First you need to get the jpeg into a BitmapImage object. It's a pretty simple task, especially if it is coming from a file.

BitmapImage sourceImage = new BitmapImage(new Uri("TestImage.jpg"));

 

Next we need to get the image into a byte array. This is a bit more complicated, but really isn't that bad

 

int stride = (sourceImage.PixelWidth * sourceImage.Format.BitsPerPixel + 7) / 8;

int size = sourceImage.PixelHeight * stride;

byte[] pixelData = new byte[size];

sourceImage.CopyPixels(pixelData, stride, 0);

 

The most complex thing here is understanding what the stride is. Stride is the number of bytes in each row of the image. We basically take the number of pixels wide and multiple that by the number of bits per pixel which is a property off of the image. Since there are 8 bits in a byte we divide by 8 to get the number of bytes. The next key thing is the size of the byte array that we need which can be calculated by the PixelHeight multiplied by the stride. Finally we copy this into an array. We now have an array of bits that constitute the image.

 

Let's assume for explanation purposes that our image is a 32bit image. That means that each pixel is "described" using 4 bytes. 1 byte is for the alpha channel, and the other three are for the RGB values. To loop through each pixel we do the following:

 

for (int i = 0; i < pixelData.Length; i += 4)

{

         byte blue = pixelData[i];

byte green = pixelData[i + 1];

byte red = pixelData[i + 2];

}

It's basically your standard for loop except we add 4 on each iteration of the loop. This is because we are looping though each pixel, but 1 pixel is represented by 4 bytes. Byte i is the blue channel, byte i + 1 is the green channel, byte i + 2 is the red channel, and finally byte i + 3 is the alpha channel. The table below represents the array for a 2 pixel wide by 8 pixel high image where each cell is a byte in the array and every four cells in 1 pixel. Hopefully this helps to visualize the layout of the data.

 

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

B

G

R

A

 

Finally while in the loop you can set each byte to the proper RGB color values to manipulate the image how you want and then you convert the array back into an image using the below code.

WriteableBitmap wBmp = new WriteableBitmap(sourceImage.PixelWidth, sourceImage.PixelHeight, sourceImage.DpiX,

sourceImage.DpiY, PixelFormats.Bgr32, null);

wBmp.WritePixels(new Int32Rect(0, 0, sourceImage.PixelWidth, sourceImage.PixelHeight), pixelData, stride, 0);

 

That's the basics of how to access the individual RGB values for each pixel in an image. It's pretty simple once you wrap you head around how each pixel relates to a byte.

Monday, 09 July 2012 17:16:07 (Central Daylight Time, UTC-05:00)  #    Comments [0] - Trackback - Save to del.icio.us - Digg This! - Follow me on Twitter

# Monday, 10 October 2011

 

Well, it has been pretty quiet on this blog for a while. It has been a busy year, including getting married, and I just haven't had the time to sit down and write up some posts. As you can see from my past postings I like to break things down with code samples and walkthroughs that let even the most inexperienced person understand what is going on, which can take some time to do. Hopefully in the future I can get a few posts up about Azure as I have been working in it a lot lately as well as some fun posts on working with the MS Kinect SDK.

This blog post is actually about my latest venture, Risiti. Our goal with Risiti is to begin streamlining the retail process buy building on the relationship that is established between a merchant and a customer at the time of purchase. The first step in building this relationship is creating an electronic receipt from the merchant for the customer. This first step is complex, but extremely beneficial to the customer allowing them to no longer worry about the frustration of paper receipts. I don't know about you, but when I make a purchase the paper receipt goes directly into my wallet, then once my wallet gets too thick they move onto the top of my dresser (see the picture below of my latest pile). Finally once the top of the dresser is covered with receipts I sort them, keeping the ones that I think I still may need, and shred the rest. Rarely do I ever buy anything that I need to return, but there is always that chance, especially around the holidays. On top of that I am a small business owner and I need to keep any receipts from business expenses, not to mention needing to save them for insurance and warranty purposes.

We're tackling this problem on two fronts. Our ultimate goal is direct integration with the merchants you shop at. We realize this is the best user experience for the customer, but unfortunately businesses, in general, can be slow to adopt new technologies like this so as we work on building our merchant network we are giving customers the ability to upload their receipts into the system themselves via email. If your receipt is already in an electronic format, say an email from your latest Amazon purchase, simply forward in the email to our system and it will take care of storing it for you. For paper receipts, just pull that camera phone out of your pocket, snap a picture of it, and email it in as an attachment from your phone.

Whereas storing your receipts electronically is a great goal, we want to go beyond that. We want to use that information to help you build a relationship with the merchants you shop at often. From the merchant standpoint, statistics indicate that it is much more difficult to gain a new customer than it is to retain an existing customer. Based on that, we want you to be able to let a merchant know if you received a poor shopping experience so that they can correct the situation before they lose you as a customer. Beyond that we would like to work with the merchants you shop at to offer you deals and discounts that may interest you based on what you have already bought from them. Don't worry; at no point will we be giving out your personally identifiable purchase information. We want our friends and family to use Risiti and that isn't how we want to be treating out friends and family.

It's a big venture that we see as being beneficial to everyone and we would really appreciate your feedback on the process. We'll be slowly sending out beta invites and making improvements based on your feedback. If you're interested in participating in the beta then head on over to the website and sign up for updates as we will be using this list to send out beta invitations. If you're not interested in participating I would still appreciate hearing your feedback on why you aren't interested. If you like the idea, head on over and like us on Facebook and follow @RisitiUSA on Twitter. Finally, when you're shopping at your favorite merchant ask them why they're not using Risiti!

Monday, 10 October 2011 21:26:37 (Central Daylight Time, UTC-05:00)  #    Comments [0] - Trackback - Save to del.icio.us - Digg This! - Follow me on Twitter
Risiti
# Sunday, 30 January 2011

I've been working on a fairly large project the last few months which required SQL replication where the server that hosted the publication didn't run on the default port. I don't know what SQL Server 2008's issue is with replication on anything besides the default port, but my windows service that handled the syncing would always error out. (I'm doing a pull subscription with SQL Express 2008 so there is no SQL Agent to handle the syncing for me.) My work around for this was to create a SQL Server Alias during installation of my application. You need to reference the dll Microsoft.SqlServer.SqlWmiManagement.dll to do this. (It's possible you may need to reference another dll, but I already had several SQL Server dlls referenced for the actual replication code I had written). This dll can be found in the SDK which you get installed when you install SQL Server 2008. Look for it in the folder that was created in your Program Files. The name space you will be working with is Microsoft.SqlServer.Management.Smo.Wmi. Below is some example code on how to do it in C#.

using Microsoft.SqlServer.Management.Smo.Wmi;

 

 public void CreateAlias()

        {

            ManagedComputer mc = new ManagedComputer();

 

            ServerAlias alias = new ServerAlias();

            alias.Parent = mc;

            alias.ServerName = Server Address;

            alias.Name = Name for your alias;

            alias.ConnectionString = Port number as string;

            alias.ProtocolName = "tcp";

            alias.Create();

        }

 

        public bool DoesAliasExist()

        {

            ManagedComputer mc = new ManagedComputer();

            bool result = false;

 

 

            foreach (ServerAlias serverAlias in mc.ServerAliases)

            {

                if(serverAlias.Name.ToUpper() == Name for your alias)

                {

                    result = true;

                }

            }

 

            return result;

        }

 

I tried using a completely different name for the alias, but couldn't get replication to work until I created the alias name as the server name, then things started working nicely. That seemed a bit strange to me as you would think I should be able to name the alias whatever I wanted. Hopefully someone else will find this helpful and it will save them some searching.

Sunday, 30 January 2011 19:28:30 (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback - Save to del.icio.us - Digg This! - Follow me on Twitter
Development | SQL Replication

Navigation
Archive
<2013 November>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2024
David A. Osborn
Sign In
Statistics
Total Posts: 70
This Year: 0
This Month: 0
This Week: 0
Comments: 33
Themes
Pick a theme:
All Content © 2024, David A. Osborn
DasBlog theme 'Business' created by Christoph De Baene (delarou)