Image processing software must meet the following requirements: how to place an image on another image, such as a company or individual logo on a large image.
In fact, the principle is very simple. Suppose we have a 800*600 big image (Bitmap B0), and we want to place a logo (Bitmap B1) at (10, 10). The size of the logo image is 150*30. It is very simple. We use the position (10, 10) of the large image as the starting position to create a 150*30 rectangle and replace the entire rectangle with the logo image.
The old rule is to use bitmapdata to help us implement this function.
// Take the rectangle area of W * h as the starting point of the big image (x, y)
Bitmapdata srcdata = b0.lockbits (New rectangle (X, Y, W, h), imagelockmode. writeonly, pixelformat. format24bpprgb );
// Retrieve the entire logo
Bitmapdata dstdata = b1.lockbits (New rectangle (0, 0, W, h), imagelockmode. readonly, pixelformat. format24bpprgb );
Unsafe
{
Byte * pin = (byte *) srcdata. scan0.topointer ();
Byte * plogo = (byte *) dstdata. scan0.topointer ();
For (INT y = 0; y {
For (INT x = 0; x <W; X ++)
{
// Copy the pixels of the logo image
Pin [0] = (byte) plogo [0];
Pin [1] = (byte) plogo [1];
Pin [2] = (byte) plogo [2];
Pin + = 3;
Plogo + = 3;
}
Pin + = srcdata. stride-W * 3;
Plogo + = dstdata. stride-W * 3;
}
B0.unlockbits (srcdata );
B1.unlockbits (dstdata );
}
In this way, the image logo function is implemented. Of course, there can also be other methods, such as using the bitblt API function or using the drawimage function of GDI +.
But there is a small problem. The logo area is always a rectangle. If my logo is a circle and I only want to show a circular logo on a large image instead of a rectangle, how can I implement it?
This problem can be understood as follows: We make the background of the logo transparent. The so-called transparency means that when two images are superimposed, the pixels in the "Transparency" area of the Upper-layer images are still replaced by the corresponding pixels of the lower-layer images. However, in the RGB mode, there is no "transparency" concept (pixelformat is used in our discussion. format24bpprgb, pixelformat. the Alpha component in format32bppargb supports "Transparency"). Therefore, we need to specify a color. Any color is treated as "Transparency.
For example, if our logo is black, you must specify black as transparent.
ModifyAlgorithmIt is also very simple. When the pixel color in the logo image is black (of course this is a parameter, you can change it yourself), you can use the color of the corresponding position of the big image instead, otherwise, use the pixel color of the logo. The following is an algorithm:
// Because it is possible to write back, the imagelockmode of the source image is readwrite this time.
Bitmapdata srcdata = b0.lockbits (New rectangle (X, Y, W, h), imagelockmode. readwrite, pixelformat. format24bpprgb );
Bitmapdata dstdata = b1.lockbits (New rectangle (0, 0, W, h), imagelockmode. readonly, pixelformat. format24bpprgb );
Unsafe
{
Byte * pin = (byte *) srcdata. scan0.topointer ();
Byte * plogo = (byte *) dstdata. scan0.topointer ();
For (INT y = 0; y {
For (INT x = 0; x <W; X ++)
{
// Determine whether the current vertex is transparent
// Obtain the current color
Color c = color. fromargb (plogo [2], plogo [1], plogo [0]);
If (! Colorissimilar (C, transcolor, Delta ))
{
// The color is not transparent. The color of B0 is replaced by the corresponding position of B1.
Pin [0] = (byte) plogo [0];
Pin [1] = (byte) plogo [1];
Pin [2] = (byte) plogo [2];
}
Pin + = 3;
Plogo + = 3;
}
Pin + = srcdata. stride-W * 3;
Plogo + = dstdata. stride-W * 3;
}
B0.unlockbits (srcdata );
B1.unlockbits (dstdata );
}
In the preceding algorithm, another small algorithm is used to determine whether the color C0 and c1 are equal. Of course, if the RGB components of the two colors are equal, they must be equal. But considering the tolerance, we need a more flexible algorithm.
We know that a color consists of three RGB components, each of which is an integer of [0,255. In this way, any color is a point in this finite space. If the similarity between two colors is within the threshold, the simplest way is to determine whether the distance between two points is within the threshold.
Space two-point distance formula: r2 = (x0-x1) 2 + (y0-y1) 2 + (z0-z1) 2
Below is my algorithm.
/// <Summary>
/// Whether the color is similar
/// </Summary>
/// <Param name = "C0"> color 0 </param>
/// <Param name = "C1"> color 1 </param>
/// <Param name = "Delta"> tolerances </param>
/// <Returns> yes/no </returns>
Public static bool colorissimilar (color C0, color C1, int delta)
{
Int r0, R1, G0, G1, B0, b1;
R0 = c0.r;
R1 = c1.r;
G0 = c0.g;
G1 = c1.g;
B0 = c0. B;
B1 = c1. B;
If (r0-r1) * (r0-r1) + (G0-G1) * (G0-G1) + (b0-b1) * (b0-b1) <= delta * delta)
{
Return true;
}
Else
{
Return false;
}
}
Finally, let's look at a situation. We need a translucent presentation of the logo, which looks like a watermark. With the experience of processing the above two images, it is difficult to realize that the new Pixel filling after mixing the original pixel and the B1 pixel of the logo image is required in the specified area of the B0 big image.
It is hard to imagine that the new pixel value should combine two factors: the big image and the logo image. The more transparent the logo image, the less affected the big image. So here we can use the weighted average method to obtain the new value after mixing.
New value = (1-Opacity %) * large image pixel value + opacity % * logo image pixel value
The complete functions are as follows:
/// <Summary>
/// Merge the two images to support opacity and transparent color.
/// </Summary>
/// <Param name = "B0"> image 1 </param>
/// <Param name = "B1"> Image 2 </param>
/// <Param name = "X"> Start coordinate x </param>
/// <Param name = "Y"> Start coordinate Y </param>
/// <Param name = "bw.alpha"> opacity of Image 2 </param>
/// <Param name = "transcolor"> colors processed as transparent colors </param>
/// <Param name = "Delta"> transparent color </param>
/// <Returns> merged image </returns>
Public static bitmap kimerge (Bitmap B0, bitmap B1, int X, int y, int b1_alpha, color transcolor, int delta)
{
If (b0.equals (null) | b1.equals (null ))
{
Return NULL;
}
Int W0 = b0.width;
Int h0 = b0.height;
Int W1 = b1.width;
Int H1 = b1.height;
Int W, h;
If (x + W1> w0)
{< br> W = W0-X;
}< br> else
{< br> W = W1;
}
If (Y + h1> h0)
{< br> H = H0-y;
}< br> else
{< br> H = h1;
}
Bitmapdata srcdata = b0.lockbits (New rectangle (X, Y, W, h), imagelockmode. readwrite, pixelformat. format24bpprgb );
Bitmapdata dstdata = b1.lockbits (New rectangle (0, 0, W, h), imagelockmode. readonly, pixelformat. format24bpprgb );
Unsafe
{
Byte * pin = (byte *) srcdata. scan0.topointer ();
Byte * plogo = (byte *) dstdata. scan0.topointer ();
for (INT y = 0; y {< br> for (INT x = 0; x {
// determine the transparent color
color C = color. fromargb (plogo [2], plogo [1], plogo [0]);
If (! Colorissimilar (C, transcolor, Delta)
{
Float bili = (float) bits alpha/(float) 255; // not transparent, weighted average
Float inbili = 1.0f-bili;
Int R, G, B;
B = (INT) (PIN [0] * inbili + plogo [0] * bili );
G = (INT) (PIN [1] * inbili + plogo [1] * bili );
R = (INT) (PIN [2] * inbili + plogo [2] * bili );
Pin [0] = (byte) B;
Pin [1] = (byte) g;
Pin [2] = (byte) R;
}
Pin + = 3;
Plogo + = 3;
}
Pin + = srcdata. stride-W * 3;
Plogo + = dstdata. stride-W * 3;
}
B0.unlockbits (srcdata );
B1.unlockbits (dstdata );
}
Return B0;
}
Of course, there are many methods. Here I will explain my point of view from the perspective of principle. Please let me know who has a better method.