How To Make Image Watermarking Work With C#
This tutorial shows how image watermarking works by implementing it with C# and we describe various purposes that watermarks have as well.
Filter by Category
This tutorial shows how image watermarking works by implementing it with C# and we describe various purposes that watermarks have as well.
This tutorial shows how to use colors for image segmentation applied in C#. I explain the basics of applying it in different color spaces.
This color image smoothing and sharpening tutorial shows how to apply convolution for blurring and sharpening images with C#.
This guide shows how to apply color histogram equalization with iterative equalization of the image by using nth root or nth power.
Color balancing is one of the processes we use to adjust images, which are either on the weaker or heavier side for any of the color channels.
This guide shows how to apply image tone corrections for flat, dark and light images. The purpose of it is to adjust brightness and contrast.
Color slicing is a color image processing technique, which only shows colors in a certain color space making objects stand out.
False color or pseudocolor image processing coupled with intensity slicing is useful for emphasizing shapes that might be hidden to our eyes.
This guide shows how to convert RGB to HSI image data and also how to convert it back from HSI to RGB to make it displayable on screen.
Adaptive median filter is much more effective at removing impulse noise, also known as salt and pepper noise, than traditional median filter.
Image watermarking is one of the tools we can use to discourage illegal duplication of our content. In essence, we’re inserting one or more images – watermarks, on top of our image. For example, you’ve probably already seen an image that has a logo displayed on top. That logo is the watermark.
Watermarks serve a couple of different purposes, but mainly for protection of their owners rights like copyright identification. There are also other uses for them. We can use them for user identification or fingerprinting, which is useful for identifying sources of illegal copies.
We can also use them for authenticity determination or in other words, we can see if an image has been altered in anyway. If it was, the watermark would have been destroyed or corrupted.
There are websites, like Unsplash.com, where we can get images for the content we’re creating, but each image has a set of rules that determine how you can use it. Watermarking enables us to embed these rules in the image itself so it serves us as a copy protection.
These kind of watermarks are most obvious and probably most common as well. Visible watermark is an opeque image, which we place on top of our image. This is also the simplest way to watermark an image and it’s performed in the spatial domain.
I wrote a function that puts a watermark on top of an image. Furthermore, we can set the opacity of the watermark with the folowing formula.
The alpha variable controls the opacity of the watermark and we need to set it between 0 and 1.
public static Bitmap AddVisibleWatermark(this Bitmap image, Bitmap watermark, double opacity)
{
int w = image.Width;
int h = image.Height;
BitmapData image_data = image.LockBits(
new Rectangle(0, 0, w, h),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int bytes = image_data.Stride * image_data.Height;
byte[] buffer = new byte[bytes];
byte[] result = new byte[bytes];
Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
image.UnlockBits(image_data);
int ww = watermark.Width;
int wh = watermark.Height;
if (w < ww || h < wh)
{
watermark = watermark.ScaleImage(w, h);
ww = watermark.Width;
wh = watermark.Height;
}
BitmapData wmark_data = watermark.LockBits(
new Rectangle(0, 0, ww, wh),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int wbytes = wmark_data.Stride * wmark_data.Height;
byte[] wbuffer = new byte[wbytes];
Marshal.Copy(wmark_data.Scan0, wbuffer, 0, wbytes);
watermark.UnlockBits(wmark_data);
result = buffer;
for (int i = 0; i < ww; i++)
{
for (int j = 0; j < wh; j++)
{
int wposition = i * 3 + j * wmark_data.Stride;
int position = i * 3 + j * image_data.Stride;
for (int k = 0; k < 3; k++)
{
result[position + k] = (byte)((1 - opacity) * result[position + k] + opacity * wbuffer[wposition + k]);
}
}
}
Bitmap res_img = new Bitmap(w, h);
BitmapData res_data = res_img.LockBits(
new Rectangle(0, 0, w, h),
ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);
Marshal.Copy(result, 0, res_data.Scan0, bytes);
res_img.UnlockBits(res_data);
return res_img;
}
As you might guess, invisible watermarks are imperceptible to human eye, but they can be recevered with a suitable decoding algorithm. We can assure invisibility of the watermark by inserting it as visually redundant information.
In other words, we clear last bits of each byte and put watermark image data in those bits. So in order to recover it, we need to 0 out bits that carry important image information and scale to full intensity range the information carried in the last least important bits.
Here is also a function that hides a watermark in those bits, with the following formula.
public static Bitmap AddInvisibleWatermark(this Bitmap image, Bitmap watermark)
{
int w = image.Width;
int h = image.Height;
BitmapData image_data = image.LockBits(
new Rectangle(0, 0, w, h),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int bytes = image_data.Stride * image_data.Height;
byte[] buffer = new byte[bytes];
byte[] result = new byte[bytes];
Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
image.UnlockBits(image_data);
int ww = watermark.Width;
int wh = watermark.Height;
if (w < ww || h < wh)
{
watermark = watermark.ScaleImage(w, h);
ww = watermark.Width;
wh = watermark.Height;
}
BitmapData wmark_data = watermark.LockBits(
new Rectangle(0, 0, ww, wh),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int wbytes = wmark_data.Stride * wmark_data.Height;
byte[] wbuffer = new byte[wbytes];
Marshal.Copy(wmark_data.Scan0, wbuffer, 0, wbytes);
watermark.UnlockBits(wmark_data);
result = buffer;
for (int i = 0; i < ww; i++)
{
for (int j = 0; j < wh; j++)
{
int wposition = i * 3 + j * wmark_data.Stride;
int position = i * 3 + j * image_data.Stride;
for (int k = 0; k < 3; k++)
{
result[position + k] = (byte)((4 * result[position + k]) / 4 + wbuffer[wposition + k] / 64);
}
}
}
Bitmap res_img = new Bitmap(w, h);
BitmapData res_data = res_img.LockBits(
new Rectangle(0, 0, w, h),
ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);
Marshal.Copy(result, 0, res_data.Scan0, bytes);
res_img.UnlockBits(res_data);
return res_img;
}
Hopefully this tutorial helped you with better understanding image watermarking.
You can also download the demonstration project and try it out yourself.