BioCore  5.0.0
A Windows .NET microscopy library and application for viewing, editing, and annotating images.
Loading...
Searching...
No Matches
QueueLinearFloodFiller.cs
Go to the documentation of this file.
1using AForge;
2using PixelFormat = AForge.PixelFormat;
3namespace BioCore
4{
9 {
10
11 //Queue of floodfill ranges. We use our own class to increase performance.
12 //To use .NET Queue class, change this to:
13 //<FloodFillRange> ranges = new Queue<FloodFillRange>();
15
16 public QueueLinearFloodFiller(AbstractFloodFiller configSource) : base(configSource) { }
17
22 public override void FloodFill(AForge.Point pt)
23 {
24 watch.Reset();
25 watch.Start();
26
27 //***Prepare for fill.
29
30 ranges = new FloodFillRangeQueue(((bitmapWidth + bitmapHeight) / 2) * 5);//new Queue<FloodFillRange>();
31
32 //***Get starting color.
33 int x = (int)pt.X; int y = (int)pt.Y;
34 int idx = CoordsToByteIndex(ref x, ref y);
35 startColor = bitmap.GetPixel((int)pt.X,(int)pt.Y);
36
37 bool[] pixelsChecked = this.pixelsChecked;
38
39 //***Do first call to floodfill.
40 LinearFill(ref x, ref y);
41
42 //***Call floodfill routine while floodfill ranges still exist on the queue
43 while (ranges.Count > 0)
44 {
45 //**Get Next Range Off the Queue
46 FloodFillRange range = ranges.Dequeue();
47
48 //**Check Above and Below Each Pixel in the Floodfill Range
49 int downPxIdx = (bitmapWidth * (range.Y + 1)) + range.StartX;//CoordsToPixelIndex(lFillLoc,y+1);
50 int upPxIdx = (bitmapWidth * (range.Y - 1)) + range.StartX;//CoordsToPixelIndex(lFillLoc, y - 1);
51 int upY = range.Y - 1;//so we can pass the y coord by ref
52 int downY = range.Y + 1;
53 int tempIdx;
54 for (int i = range.StartX; i <= range.EndX; i++)
55 {
56 //*Start Fill Upwards
57 //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
58 tempIdx = CoordsToByteIndex(ref i, ref upY);
59 if (range.Y > 0 && (!pixelsChecked[upPxIdx]) && CheckPixel(ref tempIdx))
60 LinearFill(ref i, ref upY);
61
62 //*Start Fill Downwards
63 //if we're not below the bottom of the bitmap and the pixel below this one is within the color tolerance
64 tempIdx = CoordsToByteIndex(ref i, ref downY);
65 if (range.Y < (bitmapHeight - 1) && (!pixelsChecked[downPxIdx]) && CheckPixel(ref tempIdx))
66 LinearFill(ref i, ref downY);
67 downPxIdx++;
68 upPxIdx++;
69 }
70
71 }
72
73 watch.Stop();
74 }
75
84 void LinearFill(ref int x, ref int y)
85 {
86
87 //cache some bitmap and fill info in local variables for a little extra speed
88
89 byte[] bitmapBits = this.bitmapBits;
90 bool[] pixelsChecked = this.pixelsChecked;
91 byte[] byteFillColor = this.byteFillColor.GetBytes(pixelFormat);
93 int bitmapWidth = this.bitmapWidth;
94 byte[] bt = new byte[6];
95 //***Find Left Edge of Color Area
96 int lFillLoc = x; //the location to check/fill on the left
97 int idx = CoordsToByteIndex(ref x, ref y); //the byte index of the current location
98 int pxIdx = (bitmapWidth * y) + x;//CoordsToPixelIndex(x,y);
99 while (true)
100 {
101 //**fill with the color
102 //bitmap.SetColor(x, y, this.byteFillColor);
103 if (pixelFormat == PixelFormat.Format8bppIndexed)
104 {
105 bitmapBits[idx] = byteFillColor[0];
106 }
107 else
108 if (pixelFormat == PixelFormat.Format24bppRgb)
109 {
110 bitmapBits[idx] = byteFillColor[0];
111 bitmapBits[idx + 1] = byteFillColor[1];
112 bitmapBits[idx + 2] = byteFillColor[2];
113 }
114 if (pixelFormat == PixelFormat.Format32bppArgb || pixelFormat == PixelFormat.Format32bppRgb)
115 {
116 bitmapBits[idx + 1] = byteFillColor[0];
117 bitmapBits[idx + 2] = byteFillColor[1];
118 bitmapBits[idx + 3] = byteFillColor[2];
119 }
120 else if (pixelFormat == PixelFormat.Format16bppGrayScale)
121 {
122 bitmapBits[idx] = byteFillColor[0];
123 bitmapBits[idx + 1] = byteFillColor[1];
124 }
125 else if (pixelFormat == PixelFormat.Format48bppRgb)
126 {
127 bitmapBits[idx] = byteFillColor[0];
128 bitmapBits[idx + 1] = byteFillColor[1];
129 bitmapBits[idx + 2] = byteFillColor[2];
130 bitmapBits[idx + 3] = byteFillColor[3];
131 bitmapBits[idx + 4] = byteFillColor[4];
132 bitmapBits[idx + 5] = byteFillColor[5];
133 }
134 //**indicate that this pixel has already been checked and filled
135 pixelsChecked[pxIdx] = true;
136 //**de-increment
137 lFillLoc--; //de-increment counter
138 pxIdx--; //de-increment pixel index
139 idx -= bitmapPixelFormatSize;//de-increment byte index
140 //**exit loop if we're at edge of bitmap or color area
141 if (lFillLoc <= 0 || (pixelsChecked[pxIdx]) || !CheckPixel(ref idx))
142 break;
143
144 }
145 lFillLoc++;
146
147 //***Find Right Edge of Color Area
148 int rFillLoc = x; //the location to check/fill on the left
149 idx = CoordsToByteIndex(ref x, ref y);
150 pxIdx = (bitmapWidth * y) + x;
151 while (true)
152 {
153 //**fill with the color
154 //bitmap.SetColor(x, y, this.byteFillColor);
155 if (pixelFormat == PixelFormat.Format8bppIndexed)
156 {
157 bitmapBits[idx] = byteFillColor[0];
158 }
159 else
160 if (pixelFormat == PixelFormat.Format24bppRgb)
161 {
162 bitmapBits[idx] = byteFillColor[2];
163 bitmapBits[idx + 1] = byteFillColor[1];
164 bitmapBits[idx + 2] = byteFillColor[0];
165 }
166 else
167 if (pixelFormat == PixelFormat.Format32bppArgb || pixelFormat == PixelFormat.Format32bppRgb)
168 {
169 bitmapBits[idx + 1] = byteFillColor[0];
170 bitmapBits[idx + 2] = byteFillColor[1];
171 bitmapBits[idx + 3] = byteFillColor[2];
172 }
173 else if (pixelFormat == PixelFormat.Format16bppGrayScale)
174 {
175 bitmapBits[idx] = byteFillColor[0];
176 bitmapBits[idx + 1] = byteFillColor[1];
177 }
178 else if (pixelFormat == PixelFormat.Format48bppRgb)
179 {
180 bitmapBits[idx] = byteFillColor[0];
181 bitmapBits[idx + 1] = byteFillColor[1];
182 bitmapBits[idx + 2] = byteFillColor[2];
183 bitmapBits[idx + 3] = byteFillColor[3];
184 bitmapBits[idx + 4] = byteFillColor[4];
185 bitmapBits[idx + 5] = byteFillColor[5];
186 }
187 //**indicate that this pixel has already been checked and filled
188 pixelsChecked[pxIdx] = true;
189 //**increment
190 rFillLoc++; //increment counter
191 pxIdx++; //increment pixel index
192 idx += bitmapPixelFormatSize;//increment byte index
193 //**exit loop if we're at edge of bitmap or color area
194 if (rFillLoc >= bitmapWidth || pixelsChecked[pxIdx] || !CheckPixel(ref idx))
195 break;
196
197 }
198 rFillLoc--;
199
200 //add range to queue
201 FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);
202 ranges.Enqueue(ref r);
203 }
204
207 protected bool CheckPixel(ref int px)
208 {
209 //tried a 'for' loop but it adds an 8% overhead to the floodfill process
210 /*bool ret = true;
211 for (byte i = 0; i < 3; i++)
212 {
213 ret &= (bitmap.Bits[px] >= (startColor[i] - tolerance[i])) && bitmap.Bits[px] <= (startColor[i] + tolerance[i]);
214 px++;
215 }
216 return ret;*/
217 if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed)
218 {
219 return (bitmapBits[px] >= (startColor.R - tolerance.R)) && bitmapBits[px] <= (startColor.R + tolerance.R);
220 }
221 else
222 if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
223 {
224 return (bitmapBits[px] >= (startColor.R - tolerance.R)) && bitmapBits[px] <= (startColor.R + tolerance.R) &&
225 (bitmapBits[px + 1] >= (startColor.G - tolerance.G)) && bitmapBits[px + 1] <= (startColor.G + tolerance.G) &&
226 (bitmapBits[px + 2] >= (startColor.B - tolerance.B)) && bitmapBits[px + 2] <= (startColor.B + tolerance.B);
227 }
228 else
229 if (bitmap.PixelFormat == PixelFormat.Format32bppArgb || bitmap.PixelFormat == PixelFormat.Format32bppRgb)
230 {
231 return (bitmapBits[px + 3] >= (startColor.R - tolerance.R)) && bitmapBits[px + 3] <= (startColor.R + tolerance.R) &&
232 (bitmapBits[px + 2] >= (startColor.G - tolerance.G)) && bitmapBits[px + 2] <= (startColor.G + tolerance.G) &&
233 (bitmapBits[px + 1] >= (startColor.B - tolerance.B)) && bitmapBits[px + 1] <= (startColor.B + tolerance.B);
234 }
235 else
236 if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale)
237 {
238 ushort r = BitConverter.ToUInt16(bitmapBits, px);
239 return (r >= (startColor.R - tolerance.R)) && r <= (startColor.R + tolerance.R);
240 }
241 else
242 if (bitmap.PixelFormat == PixelFormat.Format48bppRgb)
243 {
244 ushort r = BitConverter.ToUInt16(bitmapBits, px);
245 ushort g = BitConverter.ToUInt16(bitmapBits, px + 2);
246 ushort b = BitConverter.ToUInt16(bitmapBits, px + 4);
247 return (r >= (startColor.R - tolerance.R)) && r <= (startColor.R + tolerance.R) &&
248 (g >= (startColor.G - tolerance.G)) && g <= (startColor.G + tolerance.G) &&
249 (b >= (startColor.B - tolerance.B)) && b <= (startColor.B + tolerance.B);
250 }
251 throw new NotSupportedException(bitmap.PixelFormat + " not supported");
252 }
253
257 protected int CoordsToByteIndex(ref int x, ref int y)
258 {
259 return (bitmapStride * y) + (x * bitmapPixelFormatSize);
260 }
261
268 protected int CoordsToPixelIndex(int x, int y)
269 {
270 return (bitmapWidth * y) + x;
271 }
272
273 }
274
278 public struct FloodFillRange
279 {
280 public int StartX;
281 public int EndX;
282 public int Y;
283
284 public FloodFillRange(int startX, int endX, int y)
285 {
286 StartX = startX;
287 EndX = endX;
288 Y = y;
289 }
290 }
291}
OpenTK.Graphics.OpenGL.PixelFormat PixelFormat
Definition SlideGLArea.cs:8
The base class that the flood fill algorithms inherit from. Implements the basic flood filler functio...
A queue of FloodFillRanges.
FloodFillRange Dequeue()
Removes and returns the FloodFillRange at the beginning of the queue.
int Count
Returns the number of items currently in the queue.
void Enqueue(ref FloodFillRange r)
Adds a FloodFillRange to the end of the queue.
Implements the QueueLinear flood fill algorithm using array-based pixel manipulation.
int CoordsToPixelIndex(int x, int y)
Returns the linear index for a pixel, given its x and y coordinates.
QueueLinearFloodFiller(AbstractFloodFiller configSource)
int CoordsToByteIndex(ref int x, ref int y)
override void FloodFill(AForge.Point pt)
Fills the specified point on the bitmap with the currently selected fill color.
Represents a linear range to be filled and branched from.
FloodFillRange(int startX, int endX, int y)