ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 IEApplyThreshold issue
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

timfa

USA
9 Posts

Posted - Oct 24 2024 :  10:17:52  Show Profile  Reply
I think you have a potential bug in the IEApplyThreshold procedure in the imageenproc.pas unit.

I am simply performing a threshold operation where all pixels below ThresholdValue (e.g., 128) are being set to 0 or 255 in one case or the opposite 255 or 0 in an alternate case. I have a TIEBitmap object named ThresholdImage and makes the following call (the alternate case):

            ThresholdImage.Proc.Threshold(
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(255,255,255), CreateRGB(0,0,0) );

This function in turn calls:
procedure IEApplyThreshold(Bitmap: TIEBitmap; DownLimit, UpLimit, DownVal, UpVal: TRGB; X1, Y1, X2, Y2: Integer; OnProgress: TIEProgressEvent; Sender: TObject);


And in this procedure the following code executes:
for x := X1 to X2 do
    begin
      e := pRGB(ei);
      if (e^.r <= DownLimit.r) then
        e^.r := DownVal.r;
      if (e^.g <= DownLimit.g) then
        e^.g := DownVal.g;
      if (e^.b <= DownLimit.b) then
        e^.b := DownVal.b;
      if (e^.r > UpLimit.r) then
        e^.r := UpVal.r;
      if (e^.g > UpLimit.g) then
        e^.g := UpVal.g;
      if (e^.b > UpLimit.b) then
        e^.b := UpVal.b;
      inc(ei, i);
    end;


What happens in the case I presented is if the first IF for each r, g, b value is true it executes e^.r := DownVal.r which sets the value to 255. Then, further down it executes "if (e^.r > UpLimit.r)" and since we already changed e^.r in the first IF to 255, this second IF is true and sets e^.r := UpVal.r, i.e., it sets it to 0. I think this is wrong.

I think the code should be changed to:

      if (e^.r <= DownLimit.r) then
        e^.r := DownVal.r
      else if (e^.r > UpLimit.r) then
        e^.r := UpVal.r;

      if (e^.g <= DownLimit.g) then
        e^.g := DownVal.g
      else if (e^.g > UpLimit.g) then
        e^.g := UpVal.g;

      if (e^.b <= DownLimit.b) then
        e^.b := DownVal.b
      else if (e^.b > UpLimit.b) then
        e^.b := UpVal.b;

Thank you for considering this issue.


Tim F

xequte

38607 Posts

Posted - Oct 24 2024 :  18:29:59  Show Profile  Reply
Thanks for the report, Tim,

I'll need to investigate this when I am back in the office in early November.

Nigel
Xequte Software
www.imageen.com
Go to Top of Page

xequte

38607 Posts

Posted - Nov 03 2024 :  21:33:39  Show Profile  Reply
Hi Tim

Just to clarify, why are you not ordering your up/down values (i.e. CreateRGB(0,0,0) , CreateRGB(255,255,255) ) as would be expected?

Nigel
Xequte Software
www.imageen.com
Go to Top of Page

timfa

USA
9 Posts

Posted - Nov 13 2024 :  17:49:23  Show Profile  Reply
Hello Nigel,

I'm ordering the values as I am because in one case I am looking for a black object in the image or in the other case I'm looking for a white object. In either case, I want the item
found to appear in the threshold image as white and the pixels that don't pass the threshold test to be black. The code I wanted to use was:

      if aSetting.ThresholdMethod = tmManual then
      begin
         ThresholdValue := aSetting.Threshold;
         if aSetting.MeasureMethod = mmBlackCircle then
         begin
            MinThreshold := 0;
            MaxThreshold := ThresholdValue;
            ThresholdImage.Proc.Threshold(
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(255,255,255), CreateRGB(0,0,0) );
         end
         else
         begin
            MinThreshold := ThresholdValue;
            MaxThreshold := 255;
            ThresholdImage.Proc.Threshold(
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(ThresholdValue,ThresholdValue,ThresholdValue),
                        CreateRGB(0,0,0), CreateRGB(255,255,255) );
         end;

My workaround to this bug was...

         // Set all values <= MinThreshold to 0 (black), and all values > MaxThreshold
         // also to 0 (black).
         ThresholdImage.Proc.Threshold( CreateRGB(MinThreshold,MinThreshold,MinThreshold),
                        CreateRGB(MaxThreshold,MaxThreshold,MaxThreshold),
                        CreateRGB(0,0,0), CreateRGB(0,0,0) );
         // Set all non-zero values to 255 (White). (Actually, a value of 1 is unaltered.)
         ThresholdImage.Proc.Threshold( CreateRGB(0,0,0), CreateRGB(1,1,1),
                        CreateRGB(0,0,0), CreateRGB(255,255,255) );


The documentation for the Threshold procedure never says anything about expecting values to be in a certain order wrt magnitude...
"First overload assigns the DownVal color to all colors smaller or equal to DownLimit, and UpVal to all colors greater than UpLimit."
This is not the behavior of this procedure under the conditions I identified.


On another matter, it would be nice if your procedure TImageEnProc.ConvertToBWThreshold were changed to a function that returned the threshold value that was derived when the argument is -1 or -2 or the passed in value when it isn't -1 or -2.

Thank you.


Tim F
Go to Top of Page

xequte

38607 Posts

Posted - Nov 15 2024 :  18:58:36  Show Profile  Reply
Thanks for the suggestions, Tim. We have implemented both your suggested changes in the current beta. You can email me for it.


Nigel
Xequte Software
www.imageen.com
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: