DrawImage работает медленно, нужны локбиты?

Я прочитал много руководств по C# по использованию битов блокировки для управления изображениями, но я просто не знаю, как применить эту информацию в PowerShell.

Это проблема:

Высота $image1 составляет 2950 пикселей. Высота $image2 на 50 пикселей выше, 3000 пикселей. Мне нужно вписать $image2 в $image1, и я могу пропустить первые 49 строк $image2. Итак, в псевдокоде:

 For(y=0... For(x=0.... { image1(x,y) = image2(x,y+50) } ....))

Сценарий PowerShell ниже работает, но работает не очень быстро:

$rect = new-object Drawing.Rectangle 0, 0, $image1.width, $image1.height
$image1drawing.drawimage($image2, 
                         $rect, 
                         0, 50, $image2.width, ($image2.height - 50), 
                         $graphicalUnit)

Страницы, которые я нашел, такие как эта (Не удалось успешно использовать биты блокировки) или эта (https://web.archive.org/web/20121203144033/http://www.bobpowell.net/lockingbits.htm) написаны простым английским языком, но как преобразовать эту концепцию в PowerShell?


person Lunar Remedy    schedule 05.11.2014    source источник


Ответы (1)


Вы используете правильный подход. Использование DrawImage будет быстрее, чем копирование пикселей по одному. Некоторые предложения, чтобы сделать это быстрее:

  1. Попробуйте использовать Image.Clone, чтобы скопировать прямоугольник из исходного изображения, это приведет к наименьшему количеству объектов, которые вам нужно создать.
  2. Убедитесь, что вы используете тот же PixelFormat, что и исходное изображение (более быстрое копирование). В Image есть атрибут PixelFormat.
  3. Самое главное: доступ к Width и Height занимает много времени, поэтому сохраните их в локальной переменной для повторного использования. Если вы знаете их заранее, это хороший способ ускорить процесс.
  4. Не ждите чудес при соотношении ширины к высоте 4:3, каждое изображение имеет размер 3932 * 2950 * 3 (при условии 24-битного RGB) = 33 МБ на изображение. Это много данных, вы можете легко попытаться скопировать несколько концертов в зависимости от того, сколько у вас изображений.

Лучше написать простой командлет и использовать его в своем сценарии PowerShell.

Кстати, если вы все еще заинтересованы:

Использование lockbits в C# (согласно вашим примерам) зависит от небезопасного контекста и использования указателей. Я не верю, что PowerShell имеет доступ к небезопасному контексту.
Вы можете манипулировать неуправляемыми данными без использования небезопасного контекста, используя
Marshall; в частности, методы Read и Write (и вы могли бы ускорить процесс с помощью метода Copy за счет памяти).
PowerShell не задумывался как замена универсальным языкам .Net, для этого предназначены CmdLet.

person Eli Algranti    schedule 05.11.2014
comment
Хорошие советы, спасибо. Вы побудили меня сначала сделать еще некоторые настройки и перепроверить мои циклы, использование переменных и тому подобное. Просматривая темы set-put-pixel/drawimage/performance, я принял локбиты за универсальное решение всех проблем с программированием/графикой. - person Lunar Remedy; 05.11.2014
comment
LockBits не требует небезопасных операций, если вы используете Marshal.Copy для получения байтов. - person Nyerguds; 14.04.2020
comment
@Nyerguds, да, вы правы, спасибо, что указали на это. Это примеры C#, на которые ссылается оригинальный постер, в которых используется небезопасный контекст, а не биты блокировки. В следующем абзаце упоминается класс Marshall как обходной путь, но я, вероятно, недостаточно ясно выразился: вы можете использовать Marshall.Read/Marshall.Write для прямого доступа к заблокированным битам или Marshall.Copy для копирования заблокированных битов в управляемую память, манипулировать ими. их и скопируйте их обратно. В любом случае написание командлета вместо использования сценария Powershell, вероятно, является лучшим подходом. - person Eli Algranti; 15.04.2020