A faster alternative to the very slow GetPixel() and SetPixel() for .Net System.Drawing.Bitmap

Anybody who works with images often have probably come across .Net Bitmaps (System.Drawing.Bitmap) with their staggeringly slow GetPixel() and SetPixel() methods. Now, if you are going to work directly with images then you’re probably in the wrong place if you are using C# and .Net. However, sometimes you may want to do a small amount image analysis or manipulation from within .Net without the pain of having to pull in any other image libraries – but you find that GetPixel() and SetPixel() are just way too slow to use!

Now there is a faster way to access or manipulate the pixel data stored in a .Net Bitmap, that is to lock it (using LockBits()) and then directly access the raw image data in memory – you unlock it when you’re finished. This method is a lot faster than using Get/SetPixel() but is quite complicated to implement and it’s very messy to look at!

To get around this problem, and to avoid littering my code with gibberish I have written a bitmap wrapper class that wraps a bitmap, locks it, and provides it’s own GetPixel() and SetPixel() functions with which the original bitmap’s image data can be accessed. Using this class you can get fast access to a bitmap while using the familiar Get/SetPixel() paradigm – in this way it should act as a fairly easy drop in replacement for accessing the Bitmap objects directly.

The class is called BmpPixelSnoop and it is used like this:

// Calculate a simple sum over all of the pixels
// in the snooped bitmap. bitmap is a valid Bitmap object

long snoopSum = 0;

// Create a BmpPixelSnoop wrapper for bitmap
using (var snoop = new BmpPixelSnoop(bitmap))
{
    for (int j = 0; j != snoop.Height; j++)
    {
        for (int i = 0; i != snoop.Width; i++)
        {
            // We call GetPixel() on snoop rather
            // than bitmap as it's much faster!
            var col = snoop.GetPixel(i, j);

            snoopSum += col.R +
                        col.G +
                        col.B;
        }
    }
}

First a BmpPixelSnoop object is created to wrap the bitmap, GetPixel() and SetPixel() can then be called on it. When the BmpPixelSnoop object is destroyed (on leaving the using() block) the original bitmap will be unlocked. It is important to note, that while the bitmap is being snooped the original bitmap object cannot be accessed as it’s locked! Currently BmpPixelSnoop only works for bitmaps with a Pixel Format of PixelFormat.Format32bppArgb which is the default format for Bitmaps (if you don’t specify an alternative when creating them).

So for a little extra complication you get easy & fast access to the bitmap data – but how much faster than the native Get/SetPixel() is it? My (non scientific) tests seem to indicate that it’s about 10 times faster, which is fast enough for simple imaging tasks. It is still quite inefficient however, this is a result of wanting to provide the same Get/SetPixel() interface as System.Drawing.Bitmap – for example, GetPixel() always returns all of the pixel data even if you just want to access the red component and hence is slower than it needs to be in this case. I may add extra accessor methods in the future to cater for other usage patterns and greater efficiency.

The code can be found in the git-hub repo: https://github.com/kgodden/DotNetPixelSnoop.

The class is defined in BmpPixelSnoop.cs, there is also some test code to check correctness and performance in Program.cs.

Here is the code:

//   Copyright 2019 Kevin Godden
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

using System;
using System.Drawing;
using System.Drawing.Imaging;

/// 
/// Wraps a System.Drawing.Bitmap and provides faster
/// GetPixel() and SetPixel() functions for pixel access.
/// 
/// NB While the snoop object is in scope the wrapped
/// bitmap object is locked and cannot be used 
/// as normal.  Once you have finished snooping
/// on a bitmap object, dispose of the snooper to
/// unlock the bitmap and gain normal access to 
/// it again, it is best to employ the 'using' keyword
/// to effectivly manage the snooper's scope as follows:
/// 
/// 
/// using (var snoop = new BmpPixelSnoop(myBitmap))
/// { 
/// 
///     // Snoop away!
///     var pixel = snoop.GetPixel(0, 0);
///     
/// } // Snoop goes out of scope here and bitmap is unlocked
/// 
/// This class is marked as 'unsafe' so to use it in your project
/// you must have the 'Allow unsafe code' setting checked in the
/// project settings.
/// 
/// 
unsafe class BmpPixelSnoop : IDisposable
{
    // A reference to the bitmap to be wrapped
    private readonly Bitmap wrappedBitmap;

    // The bitmap's data (once it has been locked)
    private BitmapData data = null;

    // Pointer to the first pixel
    private readonly byte* scan0;

    // Number of bytes per pixel
    private readonly int depth;

    // Number of bytes in an image row
    private readonly int stride;

    // The bitmap's width
    private readonly int width;

    // The bitmap's height
    private readonly int height;

    /// 
    /// Constructs a BmpPixelSnoop object, the bitmap
    /// object to be wraped is passed as a parameter.
    /// 
    /// The bitmap to snoop
    public BmpPixelSnoop(Bitmap bitmap)
    {
        wrappedBitmap = bitmap ?? throw new ArgumentException("Bitmap parameter cannot be null", "bitmap");

        // Currently works only for: PixelFormat.Format32bppArgb
        if (wrappedBitmap.PixelFormat != PixelFormat.Format32bppArgb)
            throw new System.ArgumentException("Only PixelFormat.Format32bppArgb is supported", "bitmap");

        // Record the width & height
        width = wrappedBitmap.Width;
        height = wrappedBitmap.Height;

        // So now we need to lock the bitmap so that we can gain access
        // to it's raw pixel data.  It will be unlocked when this snoop is 
        // disposed.
        var rect = new Rectangle(0, 0, wrappedBitmap.Width, wrappedBitmap.Height);

        try
        {
            data = wrappedBitmap.LockBits(rect, ImageLockMode.ReadWrite, wrappedBitmap.PixelFormat);
        }
        catch (Exception ex)
        {
            throw new System.InvalidOperationException("Could not lock bitmap, is it already being snooped somewhere else?", ex);
        }

        // Calculate number of bytes per pixel
        depth = Bitmap.GetPixelFormatSize(data.PixelFormat) / 8; // bits per channel

        // Get pointer to first pixel
        scan0 = (byte*)data.Scan0.ToPointer();

        // Get the number of bytes in an image row
        // this will be used when determining a pixel's
        // memory address.
        stride = data.Stride;
    }

    /// 
    /// Disposes BmpPixelSnoop object
    /// 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

     /// 
    /// Disposes BmpPixelSnoop object, we unlock
    /// the wrapped bitmap.
    /// 
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (wrappedBitmap != null)
                wrappedBitmap.UnlockBits(data);
        }
        // free native resources if there are any.
    }

    /// 
    /// Calculate the pointer to a pixel at (x, x)
    /// 
    /// The pixel's x coordinate
    /// The pixel's y coordinate
    /// A byte* pointer to the pixel's data
    private byte* PixelPointer(int x, int y)
    {
        return scan0 + y * stride + x * depth;
    }

    /// 
    /// Snoop's implemetation of GetPixel() which is similar to
    /// Bitmap's GetPixel() but should be faster.
    /// 
    /// The pixel's x coordinate
    /// The pixel's y coordinate
    /// The pixel's colour
    public System.Drawing.Color GetPixel(int x, int y)
    {
        // Better do the 'decent thing' and bounds check x & y
        if (x < 0 || y < 0 || x >= width || y >= width)
            throw new ArgumentException("x or y coordinate is out of range");

        int a, r, g, b;

        // Get a pointer to this pixel
        byte* p = PixelPointer(x, y);

        // Pull out its colour data
        b = *p++;
        g = *p++;
        r = *p++;
        a = *p;

        // And return a color value for it (this is quite slow
        // but allows us to look like Bitmap.GetPixel())
        return System.Drawing.Color.FromArgb(a, r, g, b);
    }

    /// 
    /// Sets the passed colour to the pixel at (x, y)
    /// 
    /// The pixel's x coordinate
    /// The pixel's y coordinate
    /// The value to be assigned to the pixel
    public void SetPixel(int x, int y, System.Drawing.Color col)
    {
        // Better do the 'decent thing' and bounds check x & y
        if (x < 0 || y < 0 || x >= width || y >= width)
            throw new ArgumentException("x or y coordinate is out of range");

        // Get a pointer to this pixel
        byte* p = PixelPointer(x, y);

        // Set the data
        *p++ = col.B;
        *p++ = col.G;
        *p++ = col.R;
        *p = col.A;
    }

    /// 
    /// The bitmap's width
    /// 
    public int Width { get { return width; } }

    // The bitmap's height
    public int Height { get { return height; } }
}

Here is some sample output from the colsone based test program, showing relative times:

Testing GetPixel()
GetPixel() OK
Testing SetPixel()
SetPixel() OK
Testing GetPixel() Speed
Bitmap.GetPixel() took 759ms, BmpPixelSnoop.GetPixel() took 67ms
Testing SetPixel() Speed
Bitmap.SetPixel() took 907ms, BmpPixelSnoop.SetPixel() took 72ms

Boost ASIO Simple UDP Send Packet Example

Update: I have written a simple Fire-And-Forget wrapper class for sending datagrams via UDP can be found here. It handles simple transmission use cases while hiding the (sometimes confusing) boost::asio details. However, if you are interested in the details then read on!

Boost.ASIO is great but if you don’t use it everyday it can be hard to remember how to use it to do even the simplest of things. I have included below a sample of simply sending a packet via UDP (ipv4), see the function called send_message(), this example code aims to be as minimal as it can be:

Those spouting software engineering dogma will often tell you to steer well clear of UDP for the usual, well understood reasons, but for a certain type of application where very low latency is important, it just can’t be beat!!

#include 
#include 

using namespace boost::asio;

//
// Send a string via UDP to the specified destination
// ip addresss at the specified port (point-to-point
// not broadcast)
//
bool send_udp_message(const std::string& message, const std::string& destination_ip,
						const unsigned short port) {
	io_service io_service;
	ip::udp::socket socket(io_service);

	// Create the remote endpoint using the destination ip address and
	// the target port number.  This is not a broadcast
	auto remote = ip::udp::endpoint(ip::address::from_string(destination_ip), port);

	try {
	
		// Open the socket, socket's destructor will
		// automatically close it.
		socket.open(boost::asio::ip::udp::v4());

		// And send the string... (synchronous / blocking)
		socket.send_to(buffer(message), remote);
	
	} catch (const boost::system::system_error& ex) {
		// Exception thrown!
		// Examine ex.code() and ex.what() to see what went wrong!
		return false;
	}

	return true;
}

This is the bare-bones code, no error reporting etc. Also it won’t broadcast, to allow for broadcast you need to include the following two lines and supply a broadcast ip address when calling the function. Be careful if broadcasting a lot of data as it can really overload & mess-up network equipment!

socket_base::broadcast option(true);
socket.set_option(option);

Fixed – KDevelop not stopping at breakpoints on Ubuntu Mate

I couldn’t get KDevelop to stop at breakpoints even on simple ‘hello world’ C++ projects. It appeared that CMAKE_BUILD_TYPE was being correctly set and GDB worked fine from the command-line, but from within kdevelop breakpoints were never respected! I think the problem stemmed from the Cache Value for CMAKE_BUILD_TYPE being empty, this value can be seen in the Project / Open Configuration… menu:

kdevelop breakpoint broken

Following the advice from this post I added the following into the project’s CMakeLists.txt file:

# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to 'Debug' as none was specified.")
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
    "MinSizeRel" "RelWithDebInfo")
endif()

[Originally from here]

I ran clean & rebuild etc. and then cache value was set correctly to ‘Debug’ and the debugger happily stops at breakpoints!

I hope this post helps folks as I spent _ages_ trying to get the breakpoints to work!!

ExifTool- Query Exif Maker Note by ID on Command line

In Exif, each maker-note will have a unique (hex) id. ExifTool can be used to query a maker note’s contents by its id as follows:

exiftool -u -b -Unknown_0x0013 image.jpg

This will return the value for makernote id 0x0013 contained in image.jpg.

PCL LNK2001 unresolved external symbol EuclideanClusterExtraction extract()

I have been getting the following linker error when building with the Point Cloud Library (PCL 1.8.1) in Visual Studio 2017 – not at all sure why:

Error	LNK2001	unresolved external symbol "public: void __cdecl
pcl::EuclideanClusterExtraction
::extract(class std::vector > &)" ([email protected][email protected]@[email protected]@@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@@[email protected]@@Z)	

I found that to get rid of the linker error I needed to include:

#include 

Again I am not sure why, and it is not usual to have to include impl/* files? – I may look into it a bit further if I get a chance but for now I am happy that my code links!

Hack – Sleeping for less that 1 second in Shell / Bash Script

To sleep in your shell script in units of 1 second – sleep will see you right. However what if you want to sleep for less than one second, say for 200ms?

On some newer system you can do something like this and everything is fine:

sleep .2

However when I try this on my embedded busybox device I just get a response like this:

sleep .2
sleep: invalid number '.2'

So no luck there!

However there is a nice little hack using read, have a look at this:

read -p "" -t 0.2

This will wait for 200ms and then return! It waits for a line of text that never arrives, and times-out after 200ms – in effect it sleeps for 200ms. Now, if read receives a line during the 200ms it will return early, so only use it in cases where you’re sure it won’t or you might end up (temporarily) confused!

It’s not pretty but is better than nothing ;-)

Bash – send data to serial (rs232) port and wait for response

Sending data to a serial port is quite easy in Bash, for example:

echo "my packet data" > /dev/ttyS0

And you can read from a serial port using cat:

cat /dev/ttyS0

However cat must typically be run from a different shell instance as it blocks waiting for data. So is it possible to write and then read the response from a single shell instance?

Well, it is, but it requires a bit of sleight-of-hand. For example, if we start cat in the background and then send the command, cat will report the response as follows:

# Run cat in the background
cat /dev/ttyS0&

# Send the command, cat should print the response
echo "my packet data" > /dev/ttyS0

Which works but it a bit of a mouth-full! cat continues to run in the background, and will print more responses as they arrive.

But what if you want to just send one packet and then wait for a single response?

This is a bit harder, but if your response ends with an end of line character, or another known character then we can use read to help with this…

First we setup a read command in the background, unlike cat, this command will end when a response is received or when the timeout time arrives, then we can send our command:

(read -n60 -t20 RESP < /dev/ttyS0; echo $RESP)&
echo "my packet data" > /dev/ttyS0

This gets read to wait for up to 20 seconds (-t20) for a line of data (max size, 60 characters -n60) from /dev/ttyS0, which it reads into RESP, it then echos $RESP – all of this happens in the background. echo then sends the packet which will result in a response.

If your response packed ends with a character other than an EOL character then you can specify a delimiter to read using the -d command-line option.

Again it’s all a bit long winded, so we can wrap it all up in a bash script (send_tty.sh) as follows:

#!/bin/sh
#
# Send a packet to the specified serial port
# and wait for, and output the response, it is assumed
# that the response will end with an EOL character.
#
# usage: send_tty.sh  
#
# [backgound]  Wait for, and read a line from the serial port into RESP,
# max 128 characters, timeout=10s, then output $RESP
#
(read -n128 -t10 RESP < $2; echo $RESP)&

# Hack - use read to pause for 200ms to give previous
# command a chance to get started..
read -p "" -t 0.2

# Send command
printf "$1\r" > $2

# Wait for background read to complete
wait

An example of using the script:

./send_tty.sh "my-command" /dev/ttyPS0

Github repo is here

Visual Studio Paho MQTT Error C2238 unexpected token(s) preceding ‘;’

If you’re receiving errors like the following when trying to build a project in Visual Studio 2017 using the Paho C client:

Error C2238 unexpected token(s) preceding ';'

Then there is a quick fix, the problem seems to revolve around the following for DLLImport & DLLExport in the Paho header files:

#if defined(WIN32) || defined(WIN64)
  #define DLLImport __declspec(dllimport)
  #define DLLExport __declspec(dllexport)
#else
  #define DLLImport extern
  #define DLLExport __attribute__ ((visibility ("default")))
#endif

The catch here is that neither WIN32 nor WIN64 will be defined as instead either _WIN32 or _WIN64 will be defined.

So a quick fix is to define either WIN32 or WIN64 in your project’s ‘Preprocessor Definitions’ depending on whether you are targeting x86 (32bit) or x64 (64bit).

Here are some of the other errors you might see when you have this problem:

error C3861: 'visibility': identifier not found
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2059: syntax error: 'const'
error C3861: 'visibility': identifier not found
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2374: '__attribute__': redefinition; multiple initialization
note: see declaration of '__attribute__'
error C2448: '__attribute__': function-style initializer appears to be a function definition
 error C3646: 'data': unknown override specifier
 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
 error C3646: 'value': unknown override specifier
 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
 error C2143: syntax error: missing ';' before '*'
 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
 error C2238: unexpected token(s) preceding ';'
 error C3861: 'visibility': identifier not found
 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
 error C2374: '__attribute__': redefinition; multiple initialization
note: see declaration of '__attribute__'
 error C2448: '__attribute__': function-style initializer appears to be a function definition
 error C2143: syntax error: missing ',' before '*'
 error C3861: 'visibility': identifier not found
 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

PCL Octree Cheat Sheet

The point cloud library (PCL) is a fantastic resource for working with point clouds, however it is a large library and it can take a while to effectively find your way around it. The octree construct is very useful for working with point clouds, but again it can take a while to learn how to interact with octrees. To help me to remember how to interact with them I will include some examples here:

To iterate across the nodes of an octree (depth first):

//
for (auto it = octree.begin(); it != octree.end(); ++it) {
	if (it.isBranchNode()) {
		cout << "branch" << std::endl;
	}

	if (it.isLeafNode()) {
		cout << "leaf" << std::endl;
	}
}
//

To iterate across the leaf nodes:

//
for (auto it = octree.leaf_begin(); it != octree.leaf_end(); ++it) {

}
//


Get a Voxel's Bounding Region given node iterator:

//
// Get iterator to first leaf
auto it = octree.leaf_begin();

Eigen::Vector3f voxel_min, voxel_max;
octree.getVoxelBounds(it, voxel_min, voxel_max);
//

Get point indices from leaf node iterator

//
auto it = octree.leaf_begin(); 

std::vector indices;
it.getLeafContainer().getPointIndices(indices);
//

Get point indices from leaf node pointer

//
std::vector indices;

if (node->getNodeType() == LEAF_NODE)
{
	// Nasty down-cast?
	auto* l = dynamic_cast ::LeafNode*>(node);
	(*l)->getPointIndices(indices);
}
//

PCL C2988 unrecognizable template declaration/definition Visual Studio 2017

If you get this compile error:

Error C2988 unrecognizable template declaration/definition

When you:

#include 

from the Point Cloud Library (PCL) in Visual Studio 2017, then either throw the following in before the #include, like this:

//
#define BOOST_TYPEOF_EMULATION

#include 

or upgrade your version of Visual Studio 2017 (I haven’t tested this yet myself!)

Not sure why, it’s something to do with workarounds for VS 2017 bugs or something…