簡體   English   中英

C# 將圖像從彩色轉換為黑白

[英]C# Convert an image from color to a black and white

我從這里嘗試了幾個例子,但沒有找到任何有效的方法。

我需要能夠將彩色圖像轉換為黑白圖像,以便我可以獲取該數據並將其發送到熱敏打印機。

將圖像從彩色變為黑白似乎很麻煩,因為我在 C# 庫中沒有找到任何方法。

我正在測試的圖像是 PixelFormat.Format32bppArgb,我相信我想將其轉換為 PixelFormat.Format1bppIndexed

編輯:不知道如何讓它更清楚。 我不想要灰度,我想要黑白,這就是“PixelFormst.Format1bppIndexed”

您可以使用 ImageMagick 來實現,它安裝在大多數 Linux 發行版上,可免費用於 OSX(最好是通過homebrew ),也可從此處免費用於 Windows。

如果您從這個平滑的灰度漸變開始:

在此處輸入圖片說明

在命令行中,您可以將其用於 Floyd-Steinberg 抖動:

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

在此處輸入圖片說明

或者,這對於Riemersma抖動:

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

在此處輸入圖片說明

Glenn 所指的 Ordered Dither 可以像這樣使用不同的平鋪選項:

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

在此處輸入圖片說明

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

在此處輸入圖片說明

檢查格式顯示它是 1bpp,帶有 2 個調色板:

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

如果您從這樣的彩色圖像開始:

在此處輸入圖片說明

並像這樣處理:

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

你會得到這個

在此處輸入圖片說明

正如格倫所說,ImageMagick 有 C# 綁定 - 或者您可以只在批處理文件中使用上述命令,或者使用 C# 等效的system()調用來執行上述 ImageMagick 命令。

Imagemagick 可以通過各種方法將圖像轉換為黑白圖像,包括抖動 (-dither) 和有序抖動 (-ordered-dither)。 我通常使用命令行界面,但您可以嘗試使用名為 magick.net 的 C# 綁定。 參見magick.codeplex.com

有關一些示例,請參閱codegolf.stackexchange.com 上的此問答

在此處輸入圖片說明

您可以使用此代碼將圖像轉換為黑白。

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);
                }


            }

        }
    }

}
}

我相信您可以通過合適的抖動算法獲得相當好的結果。 這里有一個類似的帖子,看看是否對你有幫助:

將位圖轉換為單色

我個人會分兩步完成:

  • 使用兩種顏色的調色板將圖像轉換為 8 位圖像。
  • 將 8 位圖像轉換為 1 位圖像。

我之前已經解釋過的第一步,在這個答案中 (您可能希望使用此處其他答案中所述的更詳細的抖動方法,但即便如此,其將圖像轉換和操作為字節數組的方法也需要答案。)

詳細的基本方法是:

  • 在新的 32bpp ARGB 圖像上繪制圖像,以便您擁有可預測的每像素四字節數據結構。
  • 提取圖像的字節。
  • 從每個 4 字節的塊中制作一種顏色,將其與給定調色板上最接近的匹配項進行匹配,並將該匹配的結果存儲在一個字節數組中(具有完全的width * height字節)。
  • 使用 8 位數據數組和使用的調色板制作新圖像。

這將使您的圖片轉換為黑白8 位圖像。 現在,獲得1 位圖像所需要做的就是在最后一步之前添加一個新步驟,將 8 位數據壓縮為 1 位數據,然后使用PixelFormat.Format1bppIndexedBuildImage函數進行最后調用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;
}

顯示顏色的術語稱為灰度:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM