Combine multiple images in Emgu or opencv - c#

I have lots of colors ranges need to filter then combine achieved images to get single image contained all those filtered colors. like this:
Image<Gray, Byte> grayscale2 = frame2.Convert<Gray, Byte>();
for (int i = 1; i < colors.Length - 1; i++)
{
var color1 = colors[i].Split('-');
var color2 = colors[i+1].Split('-');
var img = frame2.InRange(new Bgr(double.Parse(color1[0]),
double.Parse(color1[1]), double.Parse(color1[2])),
new Bgr(double.Parse(color2[0]), double.Parse(color2[1]),
double.Parse(color2[2]))).Convert<Gray, Byte>();
}
"colors" is an array of RGB saved colors as string.
I am looking for the fastest way to combine (merge) all img in grayscale2.
Thank you.

I don't know exactly what do you want. I made a simple program in opencv in python. AS you have grayscale image you can add this images, but you need to remember this. If in image1 pixel has value 150 and in image2 value 150, final pixel has 255 value. So you have to add them with weight.
import cv2 as cv
import numpy as np
img1= cv.imread('image1.jpg')
img2= cv.imread('image2.jpg')
hsv1 = cv.cvtColor(img1, cv.COLOR_BGR2HSV)
hsv2 = cv.cvtColor(img2, cv.COLOR_BGR2HSV)
lower_blue = np.array([110, 50, 50])
upper_blue = np.array([130, 255, 255])
mask1 = cv.inRange(hsv1, lower_blue, upper_blue)
mask2 = cv.inRange(hsv2, lower_blue, upper_blue)
alpha=0.5
beta =0.5
output =cv.addWeighted( mask1, alpha, mask2, beta, 0.0, )
cv.imshow('av1',img1)
cv.imshow('av2',img2)
cv.imshow('av3',mask1)
cv.imshow('av4',mask2)
cv.imshow('av4',output)
cv.waitKey(0)

I did something like this by convert the images to bitmap first then combine them it's very faster:
public static Bitmap CombineBitmap(string[] files)
{
//change the location to store the final image.
Bitmap img = new Bitmap(files[0]);
Bitmap img3 = new Bitmap(img.Width, img.Height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (string file in files)
{
img = new Bitmap(file);
img.MakeTransparent(Color.White);
g.DrawImage(img, new Point(0, 0));
//img3.MakeTransparent(Color.White);
}
using (var b = new Bitmap(img3.Width, img3.Height))
{
b.SetResolution(img3.HorizontalResolution, img3.VerticalResolution);
using (var g2 = Graphics.FromImage(b))
{
g2.Clear(Color.White);
g2.DrawImageUnscaled(img3, 0, 0);
}
// Now save b as a JPEG like you normally would
return img3;
}

Related

how to have my rectangle always on the middle of the image without knowing the size of the incomming image

Trying to add a watermark image to a png image, i´ve been able to do it, but i want to take out the hardCoded size regulation for the rectangle of the waterMark, and make it always stay in the center of the image. How can i achieve this.
public Form1()
{
InitializeComponent();
picBox.Parent = this;
picBox.Dock = DockStyle.Fill;
picBox.SizeMode = PictureBoxSizeMode.Zoom;
Bitmap Jpg = new Bitmap(#"C:\Users\tferreira\Desktop\213123.PNG");
using (Bitmap Bmp = new Bitmap(#"C:\Users\tferreira\Desktop\logo.png"))
{
using (Bitmap WatermarkBmp = new Bitmap(Bmp, Bmp.Width / 1, Bmp.Height / 1))
{
picBox.Image = WatermarkImage(Jpg, WatermarkBmp, new Point(400, 100), 0.40F);
}
}
}
public Bitmap WatermarkImage(Bitmap ImageToWatermark, Bitmap Watermark, Point WatermarkPosition, float Opacity)
{
using (Graphics G = Graphics.FromImage(ImageToWatermark))
{
using (ImageAttributes IA = new ImageAttributes())
{
ColorMatrix CM = new ColorMatrix();
CM.Matrix33 = Opacity;
IA.SetColorMatrix(CM);
G.DrawImage(Watermark, new Rectangle(WatermarkPosition, Watermark.Size), 0, 0, Watermark.Width, Watermark.Height, GraphicsUnit.Pixel, IA);
}
}
return ImageToWatermark;
}
Right now the images are hardCoded but that will be taken out. If anyone can help me make this watermark allways stay centered i thank you.
I fixed this problem with this nice peace of code.
System.Drawing.Image img = System.Drawing.Image.FromFile(JpgFilePath);
Bitmap jpg = new Bitmap(img);
filePath = JpgFilePath;
int Width = jpg.Width;
int Height = jpg.Height;
jpg.SetResolution(300, 300);
WaterMarked = WatermarkImage(jpg, WaterMarkBit, new Point((Width - WaterMarkBit.Width) / 2, (Height - WaterMarkBit.Height) / 2), 0.4F);
WaterMarked.Save(filePath.Replace(".jpg", "") + ".tif", ImageFormat.Tiff);
filesJpgForTif.Add(JpgFilePath.Replace("jpg", "tif"));
Using the the sizes of the image and sizes of the watermark and divide it by 2 it makes the image always stay centered.

Concatenate a bitmap (rgb) with a TIFF (cmyk) without converting cmyk to rgb

I'm developing an application to concatenate a bitmap image in RGB with a TIFF in CMYK.
I've tried with System.Drawing and System.Windows.Media namespaces.
The problem is both the libraries try to convert my TIFF image into RGB before merging, which causes a loss in image quality.
As far as I understand, the reason they always convert images into RGB before processing because the two libraries do that with a rendering intent.
I don't need to render anything, just merge the two photos and save to disk, that's all.
What should I do to achieve my goal? Clearly, I don't want to lose the quality of the TIFF so I think it's best to not do any conversion, just keep it raw and merge. Anyway, that's just a guess, other option could be considered as well. Could anybody shed some light on my case please?
See a comparison of the tiff image before and after converted from cmyk to rgb below.
I’m not aware of any capacity in the TIFF format to have two different color spaces at the same time. Since you are dealing in CMYK, I assume that is the one you want to preserve.
If so, the steps to do so would be:
Load CMYK image A (using BitmapDecoder)
Load RGB image B (using BitmapDecoder)
Convert image B to CMYK with the desired color profile (using FormatConvertedBitmap)
If required, ensure the pixel format for image B matches A (using FormatConvertedBitmap)
Composite the two in memory as a byte array (using CopyPixels, then memory manipulation, then new bitmap from the memory)
Save the composite to a new CMYK TIFF file (using TiffBitmapEncoder)
That should be possible with WIC (System.Media).
An example doing so (github) could be written as:
BitmapFrame LoadTiff(string filename)
{
using (var rs = File.OpenRead(filename))
{
return BitmapDecoder.Create(rs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad).Frames[0];
}
}
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGB.tif");
if (imageB.PixelHeight != imageA.PixelHeight)
{
throw new InvalidOperationException("Image B is not the same height as image A");
}
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth + imageB.PixelWidth,
height = imageA.PixelHeight,
bytesPerPixel = imageA.Format.BitsPerPixel / 8,
stride = width * bytesPerPixel;
var buffer = new byte[stride * height];
imageA.CopyPixels(buffer, stride, 0);
imageBCmyk.CopyPixels(buffer, stride, imageA.PixelWidth * bytesPerPixel);
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, buffer, stride);
// save to new file
using (var ws = File.Create("out.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
Which maintains color accuracy of the CMYK image, and converts the RGB using the system color profile. This can be verified in Photoshop which shows that the each letter, and rich black, have maintained their original values. (note that imgur does convert to png with dubious color handling - check github for originals.)
Image A (CMYK):
Image B (RGB):
Result (CMYK):
To have the two images overlayed, one image would have to have some notion of transparency. A mask would be one example thereof, where you pick a particular color value to mean "transparent". The downside of a mask is that masks do not play well with aliased source images. For that, you would want to do an alpha channel - but blending across color spaces would be challenging. (Github)
// Load, validate A
var imageA = LoadTiff("CMYK.tif");
if (imageA.Format != PixelFormats.Cmyk32)
{
throw new InvalidOperationException("imageA is not CMYK");
}
// Load, validate, convert B
var imageB = LoadTiff("RGBOverlay.tif");
if (imageB.PixelHeight != imageA.PixelHeight
|| imageB.PixelWidth != imageA.PixelWidth)
{
throw new InvalidOperationException("Image B is not the same size as image A");
}
var imageBBGRA = new FormatConvertedBitmap(imageB, PixelFormats.Bgra32, null, 0d);
var imageBCmyk = new FormatConvertedBitmap(imageB, imageA.Format, null, 0d);
// Merge
int width = imageA.PixelWidth, height = imageA.PixelHeight;
var stride = width * (imageA.Format.BitsPerPixel / 8);
var bufferA = new uint[width * height];
var bufferB = new uint[width * height];
var maskBuffer = new uint[width * height];
imageA.CopyPixels(bufferA, stride, 0);
imageBBGRA.CopyPixels(maskBuffer, stride, 0);
imageBCmyk.CopyPixels(bufferB, stride, 0);
for (int i = 0; i < bufferA.Length; i++)
{
// set pixel in bufferA to the value from bufferB if mask is not white
if (maskBuffer[i] != 0xffffffff)
{
bufferA[i] = bufferB[i];
}
}
var result = BitmapSource.Create(width, height, imageA.DpiX, imageA.DpiY, imageA.Format, null, bufferA, stride);
// save to new file
using (var ws = File.Create("out_overlay.tif"))
{
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Frames.Add(BitmapFrame.Create(result));
tiffEncoder.Save(ws);
}
Example image B:
Example output:

How to remove connected objects in binary image using ConnectedComponents

I am using EmguCV and C#. I want to remove small connected objects from my image using ConnectedComponentsWithStats
I have following binary image as input
I am able to draw a rectangle for specified area. Now i want to remove objects from binary image
Here is my code
Image<Gray, byte> imgry = image.Convert<Gray, byte>();
var mask = imgry.InRange(new Gray(50), new Gray(255));
var label = new Mat();
var stats = new Mat();
var centroids = new Mat();
int labels = CvInvoke.ConnectedComponentsWithStats(mask, label, stats,
centroids,
LineType.EightConnected,
DepthType.Cv32S);
var img = stats.ToImage<Gray, int>();
Image<Gray, byte> imgout1 = new Image<Gray, byte>(image.Width, image.Height);
for (var i = 1; i < labels; i++)
{
var area = img[i, (int)ConnectecComponentsTypes.Area].Intensity;
var width = img[i, (int)ConnectecComponentsTypes.Width].Intensity;
var height = img[i, (int)ConnectecComponentsTypes.Height].Intensity;
var top = img[i, (int)ConnectecComponentsTypes.Top].Intensity;
var left = img[i, (int)ConnectecComponentsTypes.Left].Intensity;
var roi = new Rectangle((int)left, (int)top, (int)width, (int)height);
if (area > 1000)
{
CvInvoke.Rectangle(imgout1, roi, new MCvScalar(255), 1);
}
}
Drawn Rectangle for specified area
How can i remove objects of specified size
My output image should be like this
I have achieved one way by using contours it works fine for small image, when i have large image 10240*10240 and more number of particles my application entering to break mode

Change image size with C# in MVC3?

[HttpPost]
public ActionResult AddImage(Image model)
{
if (model.ImageData != null && model.ImageData.ContentLength > 0)
{
var fileName = Path.GetFileName(model.ImageData.FileName);
var pathBig = Path.Combine(Server.MapPath("~/UploadedImages"), fileName);
var pathSmall = Path.Combine(Server.MapPath("~/UploadedImages"), "small_" + fileName);
// --> How to change image size to big(800 x 600)
// and small (100x80) and save them?
model.ImageData.SaveAs(pathBig);
model.ImageData.SaveAs(pathSmall);
}
}
How do I change the image size to big(800 x 600) to small (100x80) and save them?
You could try this library:
http://nuget.org/packages/ImageResizer
It does support asp.net-mvc:
http://imageresizing.net/
Or you could get a pure C# lib and use it on your app. See these posts:
Resize an Image C#
https://stackoverflow.com/a/2861813/368070
And this snippet I found : http://snippets.dzone.com/posts/show/4336
The simplest way of doing it from the framework methods itself will be to use the DrawImage() method of the Graphics Class.
The example code could be like:
//For first scale
Bitmap bmp = new Bitmap(800, 600);
Graphics gf = Graphics.FromImage(bmp);
Image userpic = Image.FromStream(/*pass here the image byte stream*/)
gf.DrawImage(userpic, new Rectangle(0,0,800,600))
gf.Save(/* the save path */);
//For second scale
Bitmap bmp = new Bitmap(100, 80);
Graphics gf = Graphics.FromImage(bmp);
Image userpic = Image.FromStream(/*pass here the image byte stream*/)
gf.DrawImage(userpic, new Rectangle(0,0,100,80))
gf.Save(/* the save path */);

Need C# function to convert grayscale TIFF to black & white (monochrome/1BPP) TIFF

I need a C# function that will take a Byte[] of an 8 bit grayscale TIFF, and return a Byte[] of a 1 bit (black & white) TIFF.
I'm fairly new to working with TIFFs, but the general idea is that we need to convert them from grayscale or color to black and white/monochrome/binary image format.
We receive the images via a WCF as a Byte[], then we need to make this conversion to black & white in order to send them to a component which does further processing. We do not plan at this point, to ever save them as files.
For reference, in our test client, this is how we create the Byte[]:
FileStream fs = new FileStream("test1.tif", FileMode.Open, FileAccess.Read);
this.image = new byte[fs.Length];
fs.Read(this.image, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
--------update---------
I think there may be more than 1 good answer here, but we ended up using the code from the CodeProject site with the following method added to overload the convert function to accept Byte[] as well as bitmap:
public static Byte[] ConvertToBitonal(Byte[] original)
{
Bitmap bm = new Bitmap(new System.IO.MemoryStream(original, false));
bm = ConvertToBitonal(bm);
System.IO.MemoryStream s = new System.IO.MemoryStream();
bm.Save(s, System.Drawing.Imaging.ImageFormat.Tiff);
return s.ToArray();
}
There is an article on CodeProject here that describes what you need.
#neodymium has a good answer, but GetPixel/SetPixel will kill performance. Bob Powell has a great method.
C#:
private Bitmap convertTo1bpp(Bitmap img)
{
BitmapData bmdo = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
ImageLockMode.ReadOnly,
img.PixelFormat);
// and the new 1bpp bitmap
Bitmap bm = new Bitmap(img.Width, img.Height, PixelFormat.Format1bppIndexed);
BitmapData bmdn = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format1bppIndexed);
// scan through the pixels Y by X
for(int y = 0; y < img.Height; y++)
{
for(int x = 0; x < img.Width; x++)
{
// generate the address of the colour pixel
int index = y * bmdo.Stride + x * 4;
// check its brightness
if(Color.FromArgb(Marshal.ReadByte(bmdo.Scan0, index + 2),
Marshal.ReadByte(bmdo.Scan0, index + 1),
Marshal.ReadByte(bmdo.Scan0, index)).GetBrightness() > 0.5F)
{
setIndexedPixel(x, y, bmdn, true); // set it if its bright.
}
}
}
// tidy up
bm.UnlockBits(bmdn);
img.UnlockBits(bmdo);
return bm;
}
private void setIndexedPixel(int x, int y, BitmapData bmd, bool pixel)
{
int index = y * bmd.Stride + (x >> 3);
byte p = Marshal.ReadByte(bmd.Scan0, index);
byte mask = (byte)(0x80 >> (x & 0x7));
if (pixel)
{
p |= mask;
}
else
{
p &= (byte)(mask ^ 0xFF);
}
Marshal.WriteByte(bmd.Scan0, index, p);
}
might want to check out 'Craigs Utility Library' I believe he has that functionality in place.
Craig's Utility Library
My company's product, dotImage, will do this.
Given an image, you can convert from multi-bit to single bit using several methods including simple threshold, global threshold, local threshold, adaptive threshold, dithering (ordered and Floyd Steinberg), and dynamic threshold. The right choice depends on the type of the input image (document, image, graph).
The typical code looks like this:
AtalaImage image = new AtalaImage("path-to-tiff", null);
ImageCommand threshold = SomeFactoryToConstructAThresholdCommand();
AtalaImage finalImage = threshold.Apply(image).Image;
SomeFactoryToConstructAThresholdCommand() is a method that will return a new command that will process the image. It could be as simple as
return new DynamicThresholdCommand();
or
return new GlobalThresholdCommand();
And generally speaking, if you're looking to convert an entire multi-page tiff to black and white, you would do something like this:
// open a sequence of images
FileSystemImageSource source = new FileSystemImageSource("path-to-tiff", true);
using (FileStream outstm = new FileStream("outputpath", FileMode.Create)) {
// make an encoder and a threshold command
TiffEncoder encoder = new TiffEncoder(TiffCompression.Auto, true);
// dynamic is good for documents -- needs the DocumentImaging SDK
ImageCommand threshold = new DynamicThreshold();
while (source.HasMoreImages()) {
// get next image
AtalaImage image = source.AcquireNext();
AtalaImage final = threshold.Apply(image).Image;
try {
encoder.Save(outstm, final, null);
}
finally {
// free memory from current image
final.Dispose();
// release the source image back to the image source
source.Release(image);
}
}
}
First, you would need to know how an X,Y pixel location maps to an index value in you array.
This will depend upon how your Byte[] was constructed.
You need to know the details of your image format - for example, what is the stride?
I don't see 8 bit grayscale TIFF in the PixelFormat enumeration. If it was there, it would tell you what you need to know.
Then, iterate through each pixel and look at its color value.
You need to decide on a threshold value - if the color of the pixel is above the threshold, make the new color white; otherwise, make it black.
If you want to simulate grayscale shading with 1BPP, you could look at more advanced techniques, such as dithering.
Something like this might work, I haven't tested it. (Should be easy to C# it.)
Dim bmpGrayscale As Bitmap = Bitmap.FromFile("Grayscale.tif")
Dim bmpMonochrome As New Bitmap(bmpGrayscale.Width, bmpgrayscale.Height, Imaging.PixelFormat.Format1bppIndexed)
Using gfxMonochrome As Graphics = Graphics.FromImage(bmpMonochrome)
gfxMonochrome.Clear(Color.White)
End Using
For y As Integer = 0 To bmpGrayscale.Height - 1
For x As Integer = 0 To bmpGrayscale.Width - 1
If bmpGrayscale.GetPixel(x, y) <> Color.White Then
bmpMonochrome.SetPixel(x, y, Color.Black)
End If
Next
Next
bmpMonochrome.Save("Monochrome.tif")
This might be a better way still:
Using bmpGrayscale As Bitmap = Bitmap.FromFile("Grayscale.tif")
Using bmpMonochrome As New Bitmap(bmpGrayscale.Width, bmpgrayscale.Height, Imaging.PixelFormat.Format1bppIndexed)
Using gfxMonochrome As Graphics = Graphics.FromImage(bmpMonochrome)
gfxMonochrome.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
gfxMonochrome.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
gfxMonochrome.DrawImage(bmpGrayscale, new Rectangle(0, 0, bmpMonochrome.Width, bmpMonochrome.Height)
End Using
bmpMonochrome.Save("Monochrome.tif")
End Using
End Using
I believe the term you are looking for is "resampling".
pixel by pixel manipulation is extremly slow. 40 times slower than System.DrawImage.
System.Draw image is half solution, corrupts the picture (300dpi-->96dpi) and produces at 300dpi source 200-400kb large result files.
public static Image GetBlackAndWhiteImage(Image SourceImage)
{
Bitmap bmp = new Bitmap(SourceImage.Width, SourceImage.Height);
using (Graphics gr = Graphics.FromImage(bmp)) // SourceImage is a Bitmap object
{
var gray_matrix = new float[][] {
new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
new float[] { 0, 0, 0, 1, 0 },
new float[] { 0, 0, 0, 0, 1 }
};
var ia = new System.Drawing.Imaging.ImageAttributes();
ia.SetColorMatrix(new System.Drawing.Imaging.ColorMatrix(gray_matrix));
ia.SetThreshold(float.Parse(Settings.Default["Threshold"].ToString())); // Change this threshold as needed
var rc = new Rectangle(0, 0, SourceImage.Width, SourceImage.Height);
gr.DrawImage(SourceImage, rc, 0, 0, SourceImage.Width, SourceImage.Height, GraphicsUnit.Pixel, ia);
}
return bmp;
}
The perfect way is just simply convert to CCITT decoded tif, that contains only BW. Much more efficent method with 30-50kb result file, 300dpi also remains correct as well:
public void toCCITT(string tifURL)
{
byte[] imgBits = File.ReadAllBytes(tifURL);
using (MemoryStream ms = new MemoryStream(imgBits))
{
using (Image i = Image.FromStream(ms))
{
EncoderParameters parms = new EncoderParameters(1);
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders()
.FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);
parms.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
i.Save(#"c:\test\result.tif", codec, parms);
}
}
}
Good Luck Bro,
I've tested this code and worked fine for me:
//You should use System.Linq for this to work
public static ImageCodecInfo TiffCodecInfo => ImageCodecInfo.GetImageDecoders().
FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);
//Encapsulate this in a try catch block for possible exceptions
public static Bitmap ConvertToBitonal(Bitmap original)
{
EncoderParameters encoderParameters;
MemoryStream ms = new MemoryStream();
Bitmap result;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 1L);
original.Save(ms, TiffCodecInfo, encoderParameters);
result = new Bitmap(Image.FromStream(ms));
ms.Dispose();
return result;
}

Categories

Resources