Search code examples
delphiimage-processingpixel

Getting surrounding pixels color and change them


I want to make an application that first checks an image for a certain pixelcolor. When it has found an pixel with the correct pixelcolor it will 'highlight' that pixel.

But here comes the tricky part, after that i want to check the color of the 8 surrounding pixels of the 'highlighted' pixel. If one of these surrounding pixel is black, the color of that pixel should change.

I have managed to ' highlight' the pixels that have a certain pixelcolor (see code below), but i'm stuck at finding out how to check its surrounding pixels...

I hope my question is clear.

procedure Tform_Main.analyzepixels (bitmapanalyse : TBitmap);
var
C: TColor;
X, Y:Integer;
Pixels : PRGBTripleArray 
begin
  bitmapanalyse := TBitmap.Create;
  try
  bitmapanalyse.Assign(FBitmap);

  Form_memo.Memo1.Lines.BeginUpdate;
  try
  for Y := 0 to bitmapanalyse.Height - 1 do
  begin
    Pixels := bitmapanalyse.ScanLine[Y];
    ProgressBar2.StepIt;
    ProgressBar2.Update;
    Application.ProcessMessages;
    for X := 0 to bitmapanalyse.Width - 1 do
    begin
      if (Pixels[X].rgbtRed >= Pixelcolor) and 
         (Pixels[X].rgbtGreen >= Pixelcolor) and    
         (Pixels[X].rgbtBlue >= Pixelcolor)
      then
      begin
        C := RGB(
          Pixels[X].rgbtRed,
          Pixels[X].rgbtGreen,
          Pixels[X].rgbtBlue
        );

           Form_memo.Memo1.Lines.Add(
          '===============' + sLineBreak +
          'Pixel[' + IntToStr(X) + '; ' + IntToStr(Y) + ']' + sLineBreak +
          'Color: ' + ColortoString(C))

        ;
        Pixels[X].rgbtRed := 255;
        Pixels[X].rgbtGreen := 255;
        Pixels[X].rgbtBlue := 0;
      end;
    end;
  end;
finally
  Form_memo.Memo1.Lines.EndUpdate;
end;

Solution

  • I'm probably missing something, but since you have (x, y) you can obtain all surrounding pixels by simply using

    [x - 1, y - 1][x  , y - 1][x + 1, y - 1]
    [x - 1, y    ][x  , y    ][x + 1, y    ]
    [x - 1, y + 1][x  , y + 1][x + 1, y + 1]
    

    You already have logic to get a specific pixel. I'll just refactor what you have for

    function GetRGBAt(ABitmap: TBitmap; const X, Y: Integer) : PRGBTriple;
    begin
        Result := nil; // don't remember if this is necessary
        if (Y >= 0) and (X >= 0) then
        begin
            Result := aBitmap.ScanLine[Y];
            Inc(Result, X);
        end;
    end;
    
    function IsRGBBlack(ABitmap: TBitmap; const X, Y: Integer) : boolean;
    var
        P: PRGBTriple;
    begin
        P := GetRGBAt(ABitmap, X, Y);
        Result := (P <> nil) and 
                (P^.rgbtBlue + P^.rgbtGreen + P^.rgbtBlue = 0);
    end;
    

    Then you only need to add the check to your code. Since Delphi short-circuits on OR boolean expressions, the following should suffice:

    if    IsRGBBlack(bitmapanalyse, x - 1, y-1) 
       or IsRGBBlack(bitmapanalyse, x,     y-1) 
       or IsRGBBlack(bitmapanalyse, x + 1, y-1) 
    
       or IsRGBBlack(bitmapanalyse, x - 1, y) 
       // x, y not needed
       or IsRGBBlack(bitmapanalyse, x + 1, y) 
    
       or IsRGBBlack(bitmapanalyse, x - 1, y + 1) 
       or IsRGBBlack(bitmapanalyse, x,     y + 1) 
       or IsRGBBlack(bitmapanalyse, x + 1, y + 1)  then
    
    // your logic here for (x, y)
    

    This is an extremely simplistic approach, but you haven't state what you want to do in case of adjacent eligible pixels, for example, so you may need to add some extra logic for those.