.NET 4.x Поиск соседних пикселей - C#
Формулировка задачи:
Мне нужно получить цвет соседних пикселей (GetPixel). Это впринцепе почти тоже что и поиск соседних элементов в матрице, но примера на C# не смог найти, только VB. Если у кого то имеется готовое решение или есть желание помочь, буду очень признателен.
P.S. - Не первый раз сталкиваюсь с данной проблемой, каждый раз новый код получался, но ни одного красивого и одновременно быстрого способа не нашёл... Вот есть такой код, но он у меня выполняется слишком долго (много минут, даже не дождался завершения)... Предположительно там долго из-за того что исопльзую catch, но иначе не знаю как сделать...
P.P.S. - Просто экспериментирую...
Заранее спасибо!
private Color GetAverage(int x, int y) //Метод для получения среднего значения цвета соседних пикселей, x и y - пиксель соседей которого нужно найти
{
int R = 0, G = 0, B = 0;
int[,] Mas = { { -1, -1 }, //Сложно объяснить, но это я использовал чтобы находить соседние пиксели
{ 0, -1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
{ -1, 1 },
{ -1, 0 } };
for (int i = 0; i < Mas.Length; i++)
{
try //Если такого пикселя не существует, то ничего не происходит
{
R = bm.GetPixel(x + Mas[i, 0], y + Mas[i, 1]).R;
G = bm.GetPixel(x + Mas[i, 0], y + Mas[i, 1]).G;
B = bm.GetPixel(x + Mas[i, 0], y + Mas[i, 1]).B;
}
catch { }
}
return Color.FromArgb(R / 8, G / 8, B / 8);
}Решение задачи: «.NET 4.x Поиск соседних пикселей»
textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsTest {
public sealed partial class Form1 : Form {
private Bitmap _bitmap;
private Bitmap _originalBitmap;
public Form1() {
InitializeComponent();
Load += OnLoad;
}
private void OnLoad( object sender, EventArgs eventArgs ) {
const string path = "test.jpeg";
_originalBitmap = new Bitmap( path );
pictureBox1.Image = _originalBitmap;
_bitmap = (Bitmap)_originalBitmap.Clone();
}
private void buttonStart_Click( object sender, EventArgs e ) {
var kernel = new[,] {
{ textBox1.Text, textBox2.Text, textBox3.Text },
{ textBox4.Text, textBox5.Text, textBox6.Text },
{ textBox7.Text, textBox8.Text, textBox9.Text },
}.ForAll( s => int.Parse( s ) );
Stopwatch stopwatch = Stopwatch.StartNew();
_bitmap = ProcessBitmap( _bitmap, kernel );
stopwatch.Stop();
label1.Text = stopwatch.ElapsedMilliseconds.ToString();
pictureBox1.Image = _bitmap;
}
private void buttonReset_Click( object sender, EventArgs e ) {
_bitmap = _originalBitmap;
pictureBox1.Image = _bitmap;
}
private static Bitmap ProcessBitmap( Bitmap input, int[,] kernelNonscaled ) {
// Нормализуем ядро. Необходимо, чтобы сумма всех коэффициентов была равна единице.
int kernelSum = kernelNonscaled.Flatten().Sum();
var kernel = kernelNonscaled.ForAll( n => n/(double)kernelSum );
int width = input.Width;
int height = input.Height;
Rectangle rectangle = new Rectangle( 0, 0, width, height );
// Блокируем изображения в памяти.
BitmapData inputData = input.LockBits( rectangle, ImageLockMode.ReadOnly, input.PixelFormat );
// Создаём массивы с цветовыми составляющими.
int bytesCount = inputData.Stride*height;
var brgInput = new byte[bytesCount];
var brgOutput = new byte[bytesCount];
// Копируем цвета в исходный массив.
Marshal.Copy( inputData.Scan0, brgInput, 0, bytesCount );
input.UnlockBits( inputData );
// Применяем фильтр ко всем пикселям.
int stride = inputData.Stride;
Parallel.For( 1, height - 1, y => {
for ( int d = 0; d < 3; d++ ) {
for ( int x = 1; x < width - 1; x++ ) {
double result =
kernel[ 0, 0 ]*brgInput[ Pos( stride, x - 1, y - 1, d ) ] +
kernel[ 0, 1 ]*brgInput[ Pos( stride, x - 1, y, d ) ] +
kernel[ 0, 2 ]*brgInput[ Pos( stride, x - 1, y + 1, d ) ] +
kernel[ 1, 0 ]*brgInput[ Pos( stride, x, y - 1, d ) ] +
kernel[ 1, 1 ]*brgInput[ Pos( stride, x, y, d ) ] +
kernel[ 1, 2 ]*brgInput[ Pos( stride, x, y + 1, d ) ] +
kernel[ 2, 0 ]*brgInput[ Pos( stride, x + 1, y - 1, d ) ] +
kernel[ 2, 1 ]*brgInput[ Pos( stride, x + 1, y, d ) ] +
kernel[ 2, 2 ]*brgInput[ Pos( stride, x + 1, y + 1, d ) ];
int currentPosition = Pos( stride, x, y, d );
if ( result < 0 ) {
brgOutput[ currentPosition ] = 0;
}
else if ( result > 255 ) {
brgOutput[ currentPosition ] = 255;
}
else {
brgOutput[ currentPosition ] = (byte)result;
}
}
}
} );
// Создаём выходное изображение и копируем полученный массив в него.
Bitmap output = new Bitmap( width, height, input.PixelFormat );
BitmapData outputData = output.LockBits( rectangle, ImageLockMode.WriteOnly, output.PixelFormat );
Marshal.Copy( brgOutput, 0, outputData.Scan0, bytesCount );
output.UnlockBits( outputData );
return output;
}
private static int Pos( int stride, int x, int y, int d ) {
return y*stride + x*3 + d;
}
}
public static class Extensions {
public static IEnumerable<T> Flatten<T>( this T[,] arr ) {
for ( int i = 0; i < arr.GetLength( 0 ); i++ ) {
for ( int j = 0; j < arr.GetLength( 1 ); j++ ) {
yield return arr[ i, j ];
}
}
}
public static TOut[,] ForAll<TIn, TOut>( this TIn[,] arr, Func<TIn, TOut> func ) {
int n = arr.GetLength( 0 );
int m = arr.GetLength( 1 );
var result = new TOut[n,m];
for ( int i = 0; i < n; i++ ) {
for ( int j = 0; j < m; j++ ) {
result[ i, j ] = func( arr[ i, j ] );
}
}
return result;
}
}
}