public static Bitmap getGrayscale(Bitmap hc){
Bitmap result = new Bitmap(hc.Width, hc.Height);
ColorMatrix colorMatrix = new ColorMatrix(new float[][]{
new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0},
new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0,0,0,1,0,0},
new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
using (Graphics g = Graphics.FromImage(result)) {
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(hc, new Rectangle(0, 0, hc.Width, hc.Height),
0, 0, hc.Width, hc.Height, GraphicsUnit.Pixel, attributes);
}
return result;
}
Это на самом деле довольно сложная проблема.В моем примере, в основном, я создаю фильтр и применяю его к существующему растровому изображению с некоторыми изящными матричными вычислениями.Я решил это некоторое время назад, пытаясь решить эту проблему.
Редактировать
VB людям нравятся полные примеры, возможно, также делают C #.
Перетащите 2 кнопки и графическое окно на формуи используйте код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
namespace gray
{
public partial class Example : Form
{
public Example()
{
InitializeComponent();
}
public static Bitmap getGrayscale(Bitmap hc)
{
Bitmap result = new Bitmap(hc.Width, hc.Height);
ColorMatrix colorMatrix = new ColorMatrix(new float[][]{
new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0},
new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0,0,0,1,0,0},
new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
using (Graphics g = Graphics.FromImage(result))
{
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(hc, new Rectangle(0, 0, hc.Width, hc.Height),
0, 0, hc.Width, hc.Height, GraphicsUnit.Pixel, attributes);
}
return result;
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open Image File";
fDialog.Filter = "PNG Files|*.png|Bitmap Files|*.bmp";
fDialog.InitialDirectory = @"C:\";
if (fDialog.ShowDialog() == DialogResult.OK)
this.pictureBox1.ImageLocation = fDialog.FileName.ToString();
}
private void button2_Click(object sender, EventArgs e)
{
if (this.pictureBox1.Image == null)
{
MessageBox.Show("Sorry no image to alter.");
return;
}
this.pictureBox1.Image = getGrayscale((Bitmap)this.pictureBox1.Image);
}
}
}
Да, это работает, и цвета сбалансированы правильно.
Но если вам нужна альтернатива с эффективной яркостью, то:
ColorMatrix colorMatrix = new ColorMatrix(new float[][]{
new float[]{ 0.3f, 0.3f, 0.3f,0,0},
new float[]{0.59f,0.59f,0.59f,0,0},
new float[]{0.11f,0.11f,0.11f,0,0},
new float[]{ 0, 0, 0,1,0,0},
new float[]{ 0, 0, 0,0,1,0},
new float[]{ 0, 0, 0,0,0,1}});
Редактировать 2: @Hans Passant.
Растровое изображение состоит из пикселей, которые имеют цветзначение RGBA { R ed, G reen, B lue, A lpha прозрачность}.Чтобы получить изображение в градациях серого от цветного, я умножаю значение цвета каждого пикселя на свое значение colorMatrix
.
Обычное 2 умножение матрицы скорость равна is (n ^ 2), но это линейное преобразование GDI + использует Быстрое преобразование Фурье , чтобы сделать это в Θ (n log (n)).Это означает для больших изображений, это намного быстрее, чем другие методы.
Допустим, у меня есть входные пиксели In
со значениями {R, G, B, A} , и я хотел бы получить формулу для значений пикселей после умножения матрицы, и пустьНазовите это Out
со значениями {A out , B out , C out , D out } .
Out:
- A out = r (4) A + r (3) B + r (2) G + r (1) R
- B out = g (4) A + g (3) B + g (2) G + g (1) R
- C out = b (4) A + b (3) B + b (2) G + b (1) R
- D out =a (4) A + a (3) B + a (2) G + a (1) R
или в этом случае:
Out = {
0.11 B + 0.59 G + 0.3 R,
0.11 B + 0.59 G + 0.3 R,
0.11 B + 0.59 G + 0.3 R,
A,
0,
0
}
Где формула эффективной яркости изображения в градациях серого равна 0.11 blue + 0.59 green + 0.3 red
.Так что это правильно.