0

I am trying to convert some Delphi code to Python PIL. The problem is two pronged. First, I'm not a Delphi programmer. Second, I haven't used PIL before today so I may have problems in either area.

case PixelFormat of
  pf32bit: PixSize:=4;
  pf24bit: PixSize:=3;
  pf16bit: PixSize:=2;

end;
BitCounter:=0;
for i:=0 to Height-1 do begin
  Row:=ScanLine[i];
  PB:=@Row[PixSize-1];
  for j:=0 to Width-1 do begin 
    Ch[BitCounter] := (PB^ and 1);
    ....
    inc(BitCounter);
    inc(PB, PixSize);
end;

So I get that the PixelFormat attribute denotes the size of each pixel in bytes. I also get that the ScanLine method is supposed to get an array of pixels that represent the line. What I don't get is that I tend to visualize each pixel as an RGB value. I'm used to extracting the least significant bit of a color value. However, I don't think I'm even sure what the existing code is extracting. I have some python PIL code that will extract RGB values of each pixel in the same image, but I don't know how the tuple of RGB values compares to PB variable obtained in the earlier code. Based on some experiments I'm guessing that it doesn't compare at all.

Thanks in advance.

  • Your question boils down to "from which channel is the least significant bit of the most significant byte". That's well-defined, but I cannot for the life of me understand why that information could ever be useful. When would you want to know whether or not the red channel value was odd? – David Heffernan Sep 02 '12 at 07:56
  • @David, the code from this post was so weird, that I've had to Google that. It will be for [`steganography`](http://itte.no/delphi/Steganography.htm) since the code from this post is the same. user1641230, the answer you may found on the page I've linked in this comment. Interesting technique anyway... – TLama Sep 02 '12 at 18:33
  • @TLama, you are correct, it was for detecting steganography. – user1641230 Sep 02 '12 at 22:52

2 Answers2

1

In case anyone is trying to do this later. Thanks to David for the help in clarifying what ScanLine was returning.

from PIL import Image
img = Image.open('picture.gif')
(width, height) = img.size
conv = img.convert("RGB").getdata()
bt = []
for h in range(height):
  for w in range(width):
    pixel = conv.getpixel((w, h))[0]    # getpixel returns a tuple (R,G,B)
    bt.append((pixel & 0x1))
-1

It would help to show how the variables you are using are defined so we can see what you are trying to do with them. That said, the ScanLine property is an array representing the bytes representing the pixels. That said, you need a little function like your case statement to determine the number of bytes. But you need to pull each ScanLine off as a pointer to an array of bytes.

So the number of entries in the ScanLine array is Bitmap1.Height, which means you have that part right. But the rest is a little different. Let's say we define a variable named row to be a pointer. Then to find a specific pixel in the array, you have to set another pointer accordingly.

Not sure if this gets it since it's very lightly tested. I just used Longint to represent the pixel data I was pulling back. You'd use something more fitting for your needs to pull out the RGB data, but hopefully this demonstrates how to handle the ScanLine property to get the pixel data you need out of it:

var
  i, j: integer;
  row: pointer;
  pixel: pointer;
  pixelsize: integer;
  thepixel: longint;
begin
  for i := 0 to (Image1.Picture.Height - 1) do
    begin
      row := Image1.Picture.Bitmap.ScanLine[i];
      pixelsize := GetPixelSize(Image1.Picture.Bitmap.PixelFormat);
      pixel := row;
      for j := 0 to (Image1.Picture.Width - 1) do
        begin
          thepixel := Longint(Pixel^);
   //     Memo1.Lines.Add(IntToHex(thepixel, 12));
          Inc(Longint(Pixel), pixelsize);
        end;
     end;
end;
Glenn1234
  • 2,482
  • 1
  • 12
  • 19
  • 2
    How does this address the question asked (how to convert Delphi to **Python PIL**)? You basically just rewrote the Delphi code to a different Delphi code representation. – Ken White Sep 02 '12 at 03:18
  • @Glenn, Ken is correct. The Delphi code already works as posted. I am having to re-implement portions of it in Python. I have most of it working (I think), but the core problem is that I don't understand what specifically the PB variable in my original code is referencing. Is it pointing to a pixel? If so, is it the R, G, or B value specifically (or something else)? – user1641230 Sep 02 '12 at 17:35
  • PB points to a color channel. It's a pointer to a byte. It's the red channel I believe. In 16 bit colour it's the last 3 bits of the blue channel and the 5 bits of red, I believe. So I think your code always picks out the least significant bit of the red channel. – David Heffernan Sep 02 '12 at 21:41
  • @David, that was exactly what I was looking for. Thanks for the assistance. – user1641230 Sep 02 '12 at 22:45
  • @David, for 32-bit bitmap, the pixel array channel values are arranged as BGRA and when you're accessing the `[PixSize-1]` what is in this case 3, you're going to access alpha channel, don't you ? – TLama Sep 02 '12 at 23:05
  • @TLama I'm not sure. I thought alpha was the first channel. I don't know those details off top of my head. The main point is that it's the least sig bit of the last channel. – David Heffernan Sep 03 '12 at 07:00