Menu

Run Length Encode

Perrotti

The Run Length Encode is a powerful way to process binary images. It is a very simple algorithm that has been widely used to compress text and images, but later proved to be a very important tool in image processing, especially for binary images. When converting an image to RLE format is easy to detect connected objects in the image and perform a selective processing of each object.
TRunCode class can convert a binary image to RLE format and provide some features to process the objects. In the process to detect connected objects the class also extracts some characteristics that can be used to analyze objects. More advanced (and useful) characteristics can be calculated after construction.
Construction
All processing required to create the image representation in RLE and to connect the objects in the image is made during the construction of the instance. So, once the instance is created, is ready for use. The only parameter required by the constructor is the channel to be processed. The channel is considered binary. In this implementation, RLE representation of gray images is not supported.

constructor Create(Chn: TfiChannel);

Objects characteristics
An Object is a connected region of image. To store the object’s data TRunCode uses a list of TRunCodeObj instances. There are two sets of characteristics for objects. The first one is calculated by constructor and is always available. The second set depends of first set calculations and is not available until the method CalcBorderData to be called (see ahead). Below the data available on first set:
ObjID: integer;
Object ID. Each object have an integer number as identifier that don’t change until the object be destroyed. This is not the index of object. Objects are stored in a list and also have an index, but some processes needs sort the objects to be performed and the index can change.
NPix: integer;
Number of active pixels present in object (area).

Rt: TRect;
Involving rectangle of object.
AreaRt: integer;
Area of involving rectangle.
Dens: single;
Density of active pixels in object (NPix/AreaRt).
cgx, cgy: single;
Gravity center of object. Are a coordinate’s averages of all active pixels in object.
jRed, jGreen, jBlue: byte;
Random color used to represent objects in bitmaps.

User data set
The data below is also available on objects data, but are not used by classes. They are available for user processes:
TagI: int64;
TagR: extended;
Flag: boolean;
Ptr: Pointer;
Very important: If you allocate memory to Ptr pointer, you need assign a function to OnFreeObject event to free the memory when the object is destroyed.

Border characteristics set
This set of characteristics is related to borders of object and only is available after the method CalcBorderData to be called.
geoX, geoY: single;
Geometric center of object. Is the average of all pixels detected on border of object.
DistAvr: single;
Average of distances from geometric center to border pixels.

DistDev: single;
Standard deviation of distances from geometric center to border pixels. This value tells about the circularity of the object. The closer a circle is the object, smaller is this value.
Points: TPointList;
Ordered list of pixels in border of object based on TList class. The first point is the left top pixel on object and the others points are in clock-wise sequence. Points are instances of TRCPoint class declared as below:
TCPoint = class
x, y: integer;
gDist: single;
TagI: integer;
TagR: single;
constructor Create(ax, ay: integer; agDist, agAng: single);
constructor Create(pt: TCPoint);
end;
x and y are the coordinates of border pixel. gDist is the distance of pixel to geometric center (geoX, geoY). TagI and TagR are not used and are available to user processes.

ptNear, ptFar: integer;
The indexes of nearest and farthest points of border from geometric center.

Vectors: TPointList;
After calculate the border points with CalcBorderData method, you can vectorize the border by calling Vectorize method. This method copies the Points list and deletes the collinear points leaving only the points in the extremes of straight segments that surround the object. The maximum error accepted to segments is informed by parameter.
Processing objects overview
TRunCode class maintains a list of objects in ObjList field (based on TList class), so you can run the object list to access data objects and perform the process that you need. There is other list (Lines) that actually contain the RLE structure of image, ObjList only reference this structure grouping the RLE items by objects. So, is very important that you don’t delete objects using the Delete method of TList class directly from ObjList, this will cause inconsistencies on structure. To delete objects safely, TRunCode class offers DeleteObj method.
To run all objects list deleting objects by some criteria, use the method DelByUserTest. This method runs all objects and uses a call back function to decide which object will be deleted. Optionally, you can add a Single type parameters to call back function. See the example ahead.
The procedure VisitObjects works in similar way, run all objects and send then to call back function, but no action is done with objects. This is useful to analyze objects and/or assign values to user data (TagI, TagR, Flag and Ptr).
To get more information about the objects call the method CalcBorderData that provides the list of border pixels and some statistics about. You also can call method Vectorize to get a list of straight segments around the objects.
After processing, you maybe need return the RLE representation to image format, for that use the function ToImage to generate a new image or ToChannel to create a new channel. MaxVal parameter is the value used to represent active pixels on image or channel. Also you can transfer the RLE to bitmap with function ToBitmap; in this case, each object is painted with a random color. To draw all or one object in existing channel, use the methods Draw and DrawObj.

Methods reference
Procedure types
These types are used to call back functions and events.

TOnFreeObjectEvent = procedure (rcObj: TRunCodeObjData) of object;

TrcUserTestFunction = function (rcObj: TRunCodeObjData;
Param1: single=0;
Param2: single=0): boolean;

TrcVisitObjectsProc = procedure (rcObj: TRunCodeObjData;
Param1: single=0;
Param2: single=0);

To process objects

function DelByUserTest(func: TrcUserTestFunction;
Param1: single=0; Param2: single=0): integer;
Run all objects and call the function in parameter to decide which object will be deleted. Param1 and Param2 are sent to call back function.

procedure VisitObjects(proc: TrcVisitObjectsProc;
Param1: single=0; Param2: single=0);
Run all objects runs and sends them to the call back procedure informed in parameter. No action is done with objects.

function MergeObjs(ObjRemain, ObjToMerge: integer): integer;
Merge two objects. This method don’t change any pixel on image, but change the codes reference of second object to point to first object. The first characteristics set is updated to reflect the total of codes in the new object, but don’t the border data or vectors list. These features don’t support merged objects yet, but this is planned to future releases.
function MergeInnerObjs(GravCtMaxDist: single): integer;
This method merges objects whose involving rectangle is contained within the involving rectangle of other object and the distance between theirs gravity centers is less than the value informed in parameter.
function ObjAtPoint(x, y: integer): integer;
Return the ID of object at position informed or -1 if the position is background.
procedure CloseHoles;
Close the holes of all objects.
function DeleteObj(ObjID: integer): integer;
Delete the object informed. This is the only safe way to delete objects. If you use the Delete method derived from TList class, it will cause inconsistencies on run code structure.

Borders
procedure CalcBorderData;
Calculate the second set of characteristics based on border points list and generate the border points list of all objects. This feature doesn’t support merged objects in present release.
procedure Vectorize(MaxError: integer);
Perform the vectorization of border points list to all objects. This feature is only available after calculation of border points list (CalcBorderData). This method copies the border points list to Vectors field and deletes the collinear points leaving only the points in the extremes of straight segments that surround the object. The maximum error accepted to segments is informed by parameter.

Format conversions
function ToBitmap: TBitmap;
Create and return a 24 bits bitmap with all objects. Each object is drawn with a different random color.
function ToImage(Depth: integer; MaxVal: single): TFastImageEx;
Create and return a single channel image with all objects. MaxVal is the value used to represent active pixels on image.
function ToChannel(Depth: integer; MaxVal: single): TfiChannel;
Create and return a new channel with all objects. MaxVal is the value used to represent active pixels on channel.
function TaggedToChannel(Depth: integer; MaxVal: single;
TagIvalue: integer): TfiChannel;
Create and return a new channel with all objects with TagI field value equal to value informed at TagIvalue parameter. MaxVal is the value used to represent active pixels on channel.
procedure DrawObj(Dst: TfiChannel; MaxVal: single; ObjId:integer;
dx: integer=0; dy: integer = 0);
Draw the object specified at ObjID parameter in existing channel referred by Dst parameter. MaxVal is the value used to represent active pixels on channel. dx and dy is an optional offset to draw the object.
procedure Draw(Dst: TfiChannel; MaxVal: single;
dx: integer=0; dy: integer = 0);
Draw all objects in existing channel referred by Dst parameter. MaxVal is the value used to represent active pixels on channel. dx and dy is an optional offset to draw the object.

Properties / Miscellaneous
function MoveRcObj(Rc: TRunCodeCustom; ObjID: integer): integer;
Moves the object informed at ObjID parameter from Rc instance to in place instance. If the ID already exists in destination, a new ID will be created. The ID used in destination is returned by method.
function GetNewID: integer;
Return the lower unused ID.

property iSize: TfiSize;
Return the dimension of original channel that was used to create the run code.
property OnFreeObject: TOnFreeObjectEvent;
This event is called when an object is destroyed. It is usually not necessary to capture this event, but if you allocated memory for pointer Ptr (see User data set), this event offer an opportunity to free this memory.
Example:

// Function to provide a criteria to DelByUserTest method
//
function SmallArea(rcObj: TRunCodeObjData;
Param1: single=0; Param2: single=0): boolean;
begin
result:= rcObj.NPix < Param1;
end;

procedure TForm1.ProcessRunCode;
var fImg, fOut: TFastImgEx;
Rc: TRunCode;
bmp: TBitmap;
begin
[…]

// creates run code from first channel of fImg
Rc:= TRunCode.Create(fImg[0]);

// Delete all objects with area less than 10
Rc.DelByUserTest(SmallArea, 10);

// Merge the inner objects witch center gravity is close
Rc.MergeInnerObjs(10);

// Creates a new image to store process result
fOut:= Rc.ToImage(fi_8U, 255);

// Creates a bitmap from Rc
bmp := Rc.ToBitmap;

[…]

Rc.Free;
end;


Related

Wiki: Home

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.