У меня есть метод в моей программе C # WinForms, который проверяет, есть ли в столбце X изображения черные пиксели или нет.
static Boolean GetColumnState(Bitmap bmp, int x, int col)
{
BitmapData pixelData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
Boolean state = false;
unsafe
{
int* pData = (int*)pixelData.Scan0.ToPointer();
pData += x;
for (int i = 0; i < bmp.Height; ++i)
{
pData += bmp.Width;
if (Color.FromArgb(*pData) == Color.FromArgb(255, col, col, col)) // error here
{ state = true; break; }
}
}
bmp.UnlockBits(pixelData);
return state;
}
К сожалению, я получаю
«Попытка чтения или записи в защищенную память» Ошибка
at "(Color.FromArgb (* pData) == Color.FromArgb (255, col, col, col))" line
Вот как я определяю «col» из другого метода:
if (GetColumnState(b1, 0, 255) == false)
{ col = 255; }
else {col = 0;}
// more code + loops
GetColumnState(b1, i, col)
Странная вещь: я получаю ошибки, только если цвет пикселя определен как 255 (т.е. черный) ..
Как вы это объясните? Обратите внимание, что я пишу программу распознавания текста, поэтому загружаю несколько словарей с разными значениями ключей. Я много обрезаю изображения во время распознавания.
Мое счастливое предположение, что потоки портят друг друга.
Теперь я нашел способ исправить эту проблему, но цена составляет + ~ 150-200мс к общему времени выполнения скрипта (я думаю, что это ненужная цена).
Обычно я загружаю словари вот так:
Dictionary<string, Bitmap> lookup = new Dictionary<string, Bitmap>();
Bitmap l0 = new Bitmap(@"C:\xxx\0.bmp", true);
//+15 more
lookup.Add("0", l0);
//+15 more
Dictionary<string, Bitmap> lookup2 = new Dictionary<string, Bitmap>();
Bitmap nAa = new Bitmap(@"C:\yyy\Aa.bmp", true);
//+15 more
lookup2.Add("A", nAa);
//+15 more
Чтобы решить эту проблему, я должен создать «пустоты» для каждого словаря и загрузить их в разные потоки, например:
void loadNumbers1()
{
lookup4 = new Dictionary<string, Bitmap>();
Bitmap sd = new Bitmap(@"C:\xxxxx\a.bmp", true);
//+15 more
lookup4.Add("0", s0);
//+15 more
}
void loadNumbers2()// 4, 5, 6,
{
//repeat
}
Теперь мы запускаем темы:
Thread tNum2= new Thread(new ThreadStart(loadNumbers2));
tNum2.Start();
Thread tNum3= new Thread(new ThreadStart(loadNumbers3));
tNum3.Start();
Последний шаг ( без этого шага программа работает быстрее, но ошибка возникает чаще ):
tNum3.Join();
Вот и все, теперь у меня нет проблем, но время выполнения больше .. Есть идеи, как решить эту проблему более простым способом, без использования нескольких потоков? В моем случае без join () я получаю 5-100мс время загрузки словаря, с join () - до 300мс. Без потоков - до 180 (в случае, если ошибка не возникает).
Извините за длинный пост
РЕДАКТИРОВАТЬ: (постоянное исправление)
static unsafe Boolean GetColumnState(Bitmap bmp, int x, int col)
{
BitmapData pixelData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
Boolean state = false;
unsafe
{
byte[] buffer = new byte[pixelData.Height * pixelData.Stride];
Marshal.Copy(pixelData.Scan0, buffer, 0, buffer.Length);
for (int i = 0; i < pixelData.Height - 1; ++i)
{
byte red = buffer[i * pixelData.Stride + 4 * x + 2];
if (red == col)
{ state = true; break; }
}
}
bmp.UnlockBits(pixelData);
return state;
}
Я не понимаю, что такого плохого в указателях, но байты работают отлично. @ tia спасибо за указание на мою проблему.
Кто-нибудь знает, почему многопоточность замедляет время загрузки словаря, а не ускоряет его?