C#将图像从彩色转换为黑白图像

时间:2015-06-30 21:13:19

标签: c# image-processing

我从这里尝试了几个例子,但没有发现任何可行的例子。

我需要能够将彩色图像转换为黑白图像,以便我可以将这些数据发送到热敏打印机。

将图像从彩色变为黑白似乎是麻烦,因为我在C#库中找不到任何方法。

我正在测试的图像是PixelFormat.Format32bppArgb,我相信我想将其转换为PixelFormat.Format1bppIndexed

编辑:不知道如何让它更清晰。我不想灰度我想黑白这就是“PixelFormst.Format1bppIndexed”

6 个答案:

答案 0 :(得分:1)

Imagemagick可以通过各种方法将图像转换为黑白图像,包括抖动(-dither)和有序抖动(-ordered-dither)。我通常使用命令行界面,但有一个名为magick.net的C#绑定可能会尝试。请参阅magick.codeplex.com

有些例子,请参阅codegolf.stackexchange.com

上的此问答

答案 1 :(得分:1)

您可以使用安装在大多数Linux发行版上的ImageMagick,并且可以免费获得OSX(理想情况下通过homebrew)以及here中的Windows。

如果从这个平滑的灰度渐变开始:

enter image description here

在命令行中,您可以将此用于Floyd-Steinberg抖动:

convert grey.png -dither FloydSteinberg -monochrome fs.bmp

enter image description here

或者,这适用于Riemersma抖动:

convert grey.png -dither Riemersma -monochrome  riem.bmp

enter image description here

格伦所指的有序抖动可以像这样使用不同的磁贴选项:

convert grey.png -ordered-dither o8x8  -monochrome  od8.bmp

enter image description here

convert grey.png -ordered-dither o2x2  -monochrome  od2.bmp

enter image description here

格式检查显示它是1bpp,带有双色调色板:

identify -verbose riem.bmp

Image: riem.bmp
  Format: BMP (Microsoft Windows bitmap image)
  Class: PseudoClass
  Geometry: 262x86+0+0
  Units: PixelsPerCentimeter
  Type: Bilevel
  Base type: Bilevel                     <--- 1 bpp
  Endianess: Undefined
  Colorspace: Gray
  Depth: 1-bit                           <--- 1 bpp
  Channel depth:
    gray: 1-bit
  Channel statistics:
    Pixels: 22532
    Gray:
      min: 0 (0)
      max: 1 (1)
      mean: 0.470486 (0.470486)
      standard deviation: 0.499128 (0.499128)
      kurtosis: -1.98601
      skewness: 0.118261
      entropy: 0.997485
  Colors: 2
  Histogram:
     11931: (  0,  0,  0) #000000 gray(0)
     10601: (255,255,255) #FFFFFF gray(255)
  Colormap entries: 2
  Colormap:
         0: (  0,  0,  0) #000000 gray(0)        <--- colourmap has only black...
         1: (255,255,255) #FFFFFF gray(255)      <--- ... and white

如果你从这样的彩色图像开始:

enter image description here

并按此处理:

convert colour.png -ordered-dither o8x8  -monochrome  od8.bmp

你会得到这个

enter image description here

正如Glenn所说,ImageMagick有C#绑定 - 或者您可以在批处理文件中使用上述命令,或使用system()调用的C#等效执行上述ImageMagick命令。

答案 2 :(得分:1)

enter image description here

您可以使用此代码将图像转换为黑白图像。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Converting_Image_to__Black_and_White
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public static int siyahbeyazsinirnoktasi=0;
    public static string DosyaYolu = "";

    #region resim üzerinde işlemler yapma (siyah beyaz)

    Bitmap BlackandWhite(Bitmap Goruntu)

    {


        Bitmap yeniGoruntu = new Bitmap(Goruntu.Width, 
     Goruntu.Height);//Bitmap sınıfımızı oluşturduk.



        double toplampikselsayisi = Goruntu.Width * Goruntu.Height;
        int GriTonlama;



        for (int i = 0; i < Goruntu.Width; i++)//resmi yatay olarak 
taramak için

        {

            for (int j = 0; j < Goruntu.Height; j++)//resmi dikey olarak 
taramak için

            {

                Color Pixel = Goruntu.GetPixel(i, j);//color sınıfını ile 
pixel rengini alıyoruz.

                GriTonlama = (Pixel.R + Pixel.G + Pixel.B) / 3;//almış 
olduğumuz renk değerini gri tona çevirmek için kullanmamız gereken 
formül.

                if (GriTonlama < siyahbeyazsinirnoktasi)
                {

                    yeniGoruntu.SetPixel(i, j, Color.FromArgb(0, 0, 
0));//yeni görüntümüze gri tonlamadaki pixel değerini veriyoruz.
                }

                if (GriTonlama >= siyahbeyazsinirnoktasi)
                {

                    yeniGoruntu.SetPixel(i, j, Color.FromArgb(255, 255, 
255));//yeni görüntümüze gri tonlamadaki pixel değerini veriyoruz.
                }


            }


        }


        return yeniGoruntu;
    }
    #endregion


    private void btnLoadImage_Click(object sender, EventArgs e)
    {



        FolderBrowserDialog Klasor = new FolderBrowserDialog();
        openFileDialog1.Title = "Resimdosyası seçiniz.";
        openFileDialog1.Filter = "Image files (*.jpg)|*.jpg|Tüm 
dosyalar(*.*)|*.*";
        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
             DosyaYolu = openFileDialog1.FileName;
            var dosyaboyutu = new FileInfo(DosyaYolu).Length;


            if (dosyaboyutu <= 500000)
            {
                pictureBox1.Image = new 
Bitmap(openFileDialog1.OpenFile());
                btnConvertBlackandWhite.Enabled = true;
                label1.Visible = true;
                label2.Visible= true;
                label3.Visible = true;
                label4.Visible = true;
                label5.Visible = true;
                label6.Visible = true;
                trackBar1.Visible = true;

            }

            else
            {
                MessageBox.Show("Seçtiğiniz resim boyutu 500 KB'nın 
altında olmalıdır.");
            }

        }

    }

    private void btnConvertBlackandWhite_Click(object sender, EventArgs 
 e)
    {
        pictureBox1.Image = BlackandWhite(new Bitmap(DosyaYolu));
        btnSave.Enabled = true;

    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        siyahbeyazsinirnoktasi = trackBar1.Value ;
        label3.Text = Convert.ToString(siyahbeyazsinirnoktasi);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        label3.Text = "130";
        siyahbeyazsinirnoktasi = 130;
    }

    private void btnSave_Click(object sender, EventArgs e)
    {
        {

            Image pngoptikform = new Bitmap(pictureBox1.Image);
            SaveFileDialog sf = new SaveFileDialog();//yeni bir kaydetme 
diyaloğu oluşturuyoruz.

            sf.Filter = "Image file (Jpg dosyası (*.jpg)|*.jpg  ";//.bmp 
veya .jpg olarak kayıt imkanı sağlıyoruz.

            sf.Title = "Kayıt";//diğaloğumuzun başlığını belirliyoruz.

            sf.CheckPathExists = true;
            sf.DefaultExt = "jpg";
            sf.FilterIndex = 1;


            DialogResult sonuc = sf.ShowDialog();

            if (sonuc == DialogResult.OK)
            {

                if (sf.FilterIndex == 1)
                {
                    pngoptikform.Save(sf.FileName);
                    System.Diagnostics.Process.Start(sf.FileName);
                }


            }

        }
    }

}
}

答案 3 :(得分:0)

我相信你可以通过一个像样的抖动算法获得相当不错的结果。这里有类似的帖子,请看看它是否对您有所帮助:

Converting a bitmap to monochrome

答案 4 :(得分:0)

我个人分两步完成这项工作:

  • 将图像转换为带有两种颜色调色板的8位图像。
  • 将8位图像转换为1位图像。

我之前已经解释过的第一步,this answer。 (您可能希望使用更详细的抖动方法,如此处的其他答案中所述,但即使这样,其方法也需要答案将图像转换和操作为字节数组。)

详细说明的基本方法是:

  • 在新的32bpp ARGB图像上绘制图像,以便拥有可预测的每像素四字节数据结构。
  • 提取图像的字节。
  • 从每个4字节的块中生成一个颜色,将其与给定调色板上最接近的匹配相匹配,并将该匹配的结果存储在一个字节数组中(精确width * height个字节)。
  • 使用8位数据数组和使用过的调色板创建新图像。

将您的照片转换为黑白 8位图像。现在,我们需要做的就是获得一个 1位图像,在最后一步之前迈出新的一步,我们将8位数据压缩为1位数据,然后进行最后的调用改为使用BuildImage PixelFormat.Format1bppIndexed功能。

这是将图像缩小到较低位长度的功能。它需要原始图像数据和步幅,并将返回转换后的图像数据和新步幅。

注意,我不确定数据字节内的位顺序对于普通的dotNet 1位图像是什么,因为我只使用此函数来转换自定义游戏文件格式,因此您只需要测试它以查看您需要在bigEndian参数中给出的内容。如果给出错误的值,则每个8像素的列将被左右镜像,因此在结果中应该是显而易见的。

/// <summary>
/// Converts given raw image data for a paletted 8-bit image to lower amount of bits per pixel.
/// </summary>
/// <param name="data8bit">The eight bit per pixel image data</param>
/// <param name="width">The width of the image</param>
/// <param name="height">The height of the image</param>
/// <param name="bitsLength">The new amount of bits per pixel</param>
/// <param name="bigEndian">True if the bits in the new image data are to be stored as big-endian.</param>
/// <param name="stride">Stride used in the original image data. Will be adjusted to the new stride value.</param>
/// <returns>The image data converted to the requested amount of bits per pixel.</returns>
public static Byte[] ConvertFrom8Bit(Byte[] data8bit, Int32 width, Int32 height, Int32 bitsLength, Boolean bigEndian, ref Int32 stride)
{
    Int32 parts = 8 / bitsLength;
    // Amount of bytes to write per width. This rounds the bits up to the nearest byte.
    Int32 newStride = ((bitsLength * width) + 7) / 8;
    // Bit mask for reducing original data to actual bits maximum.
    // Should not be needed if data is correct, but eh.
    Int32 bitmask = (1 << bitsLength) - 1;
    Byte[] dataXbit = new Byte[newStride * height];
    // Actual conversion porcess.
    for (Int32 y = 0; y < height; y++)
    {
        for (Int32 x = 0; x < width; x++)
        {
            // This will hit the same byte multiple times
            Int32 indexXbit = y * newStride + x / parts;
            // This will always get a new index
            Int32 index8bit = y * stride + x;
            // Amount of bits to shift the data to get to the current pixel data
            Int32 shift = (x % parts) * bitsLength;
            // Reversed for big-endian
            if (bigEndian)
                shift = 8 - shift - bitsLength;
            // Get data, reduce to bit rate, shift it and store it.
            dataXbit[indexXbit] |= (Byte)((data8bit[index8bit] & bitmask) << shift);
        }
    }
    stride = newStride;
    return dataXbit;
}

答案 5 :(得分:-1)

显示颜色的术语称为灰度:

快速搜索:color to gray scale converter c#产生了以下网站:http://www.codeproject.com/Questions/315939/How-To-Convert-Grayscale-Image-to-Color-Image-in-c