Использование Bitmap.LockBits и Marshal.Copy в IronPython не меняет изображение должным образом - PullRequest
1 голос
/ 03 апреля 2010

Я написал следующий код IronPython:

import clr
clr.AddReference("System.Drawing")
from System import *
from System.Drawing import *
from System.Drawing.Imaging import *

def NoWorko(bitmap):
    bmData = bitmap.LockBits(Rectangle(0, 0, bitmap.Width, bitmap.Height), 
        ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)

    total_bytes = (bmData.Stride) * bmData.Height
    rgbValues = Array.CreateInstance(Byte, total_bytes)
    Runtime.InteropServices.Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes)
    for i in rgbValues:
        i = 255 - i

    #The following line doesn't appear to actually copy the bits back
    Runtime.InteropServices.Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes)
    bitmap.UnlockBits(bmData)

originalImage = Bitmap("Test.bmp")
newPic = NoWorko(originalImage)
newPic.Save("New.bmp")

Моя интерпретация этого примера кода MSDN: http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx, за исключением того, что я сохраняю измененное растровое изображение вместо его отображения в форме.

Код выполняется, однако вновь сохраненное растровое изображение является точной копией исходного изображения без признаков каких-либо изменений (предполагается создать красный оттенок) . Кто-нибудь может посоветовать, что не так с моим кодом?

Используемое изображение - это просто растровое изображение 24bpp, которое я создал в Paint (это просто большой белый прямоугольник!) с использованием IronPython 2.6 и Windows 7 (x64) с установленным .Net Framework 3.5 SP1.

Обновление

Моя глупость была подчеркнута при попытке добавить красный оттенок к белому изображению - так что теперь код просто инвертирует цвета. Я пробовал это на нескольких изображениях, но, похоже, это не дает никакого эффекта.

Тем не менее, следующая (очень похожая) программа на C #:

public static void Main(string[] args)
        {
            Bitmap bitmap = new Bitmap("nTest.jpg");
            BitmapData bmData = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
                    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int total_bytes = (bmData.Stride) * bmData.Height;
            byte[] rgbValues = new byte[total_bytes];

            Marshal.Copy(bmData.Scan0, rgbValues, 0, total_bytes);

            for(int i = 0; i < total_bytes; i++)
            {
                rgbValues[i] = (byte)(255 - rgbValues[i]);
            }

            Marshal.Copy(rgbValues, 0, bmData.Scan0, total_bytes);
            bitmap.UnlockBits(bmData);

            bitmap.Save("nNew.jpg");

        }

Работал над всеми изображениями, которые я пробовал.

Я не уверен, но, похоже, что-то связано с призывом:

Runtime.InteropServices.Marshal.Copy (rgbValues, 0, bmData.Scan0, bytes)

в МПГ, который вызывает проблему.

Ответы [ 2 ]

1 голос
/ 04 апреля 2010

Я не знаю Python, поэтому понятия не имею, как

for i in rgbValues[::3]: 
        i = 255 

должен работать. Но при условии, что он фактически устанавливает каждый третий байт в 255, у вас есть две проблемы:

  1. Нельзя придать белому цвету красный оттенок, установив для его красного компонента значение 255, поскольку оно уже имеет это значение. Вместо этого вы должны уменьшить синий и зеленый компоненты.
  2. Вы не можете написать код, который пытается изменить все пиксели растрового изображения одновременно, если ваш формат 24bpp ( будет работать с 32bpp) Вы должны сделать это путем сканирования строки за строкой сканирования.
0 голосов
/ 04 апреля 2010

Спасибо Дэнбистрому за то, что он заставил меня пойти и проверить это - это был мой синтаксис цикла for, который был весь перепутан, когда я был уверен, что понял это правильно. Правильный синтаксис должен был быть:

for y in range(bmData.Height):
    for x in range(bmData.Width):
        rgbValues[(bmData.Stride * y) + (3 * x) +2] = 255

D'Oh! Но это говорит о том, что другие люди спрашивают, что вы делаете:)

...