|
I am attempting to write my own flood fill algorithm, but it is proving to be pretty slow. I am wondering if anyone has an idea on how I can improve performance. Currently, I am using the 4-way non-recursive scanline algorithm, based on a Queue<Point>. I am using the WinAPI methods CreateCompatibleDC, GetPixel, SetPixel, and BitBlt. I have a feeling that if I can copy the bitmap to a byte array, then modify that array directly, then return the array to the bitmap, I can get better performance. Does anyone know how to do this, or have any other ideas as to how I can improve the following code? I copied my code below for examination (note that all the colors I am filling are gray, so R=G=B all the time, if it is a valid fill). Thanks,
private static int ToRGB(Color col) {
return (col.B << 16 | col.G << 8 | col.R);
}
private static bool AreEqual(ref int known, int other) {
if (known == other)
return true;
if ((other & 0xFF) != (other >> 8 & 0xFF) ||
(other & 0xFF) != (other >> 16 & 0xFF) ||
(other & 0xFF) < (known & 0xFF) - 2 ||
(other & 0xFF) > (known & 0xFF) + 2)
return false;
known = other;
return true;
}
private static bool FloodFill(Bitmap img, Point loc, Color fillColor) {
Graphics g = null;
IntPtr hdc1 = IntPtr.Zero, hdc2 = IntPtr.Zero;
try {
g = Graphics.FromImage(img);
hdc1 = g.GetHdc();
Color temp = ((Bitmap)img).GetPixel(loc.X, loc.Y);
hdc2 = WinAPI.CreateCompatibleDC(hdc1);
WinAPI.SelectObject(hdc2, img.GetHbitmap());
int oldColor = WinAPI.GetPixel(hdc2, loc.X, loc.Y);
if ((oldColor & 0xFF) != (oldColor >> 8 & 0xFF) ||
(oldColor & 0xFF) != (oldColor >> 16 & 0xFF))
return false;
Queue<Point> pixels = new Queue<Point>(128);
pixels.Enqueue(loc);
int x, y, newColor = ToRGB(fillColor);
bool spanL, spanR;
do {
loc = pixels.Dequeue();
x = loc.X;
y = loc.Y;
oldColor = WinAPI.GetPixel(hdc2, x, y);
while (y > 0) {
if (!AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x, --y))) {
++y;
break;
}
}
spanL = spanR = false;
do {
int res = WinAPI.SetPixel(hdc2, x, y, newColor);
if (!spanL) {
if (x > 0 && AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x - 1, y))) {
pixels.Enqueue(new Point(x - 1, y));
spanL = true;
}
} else if (!AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x - 1, y))) {
spanL = false;
}
if (!spanR) {
if (x < img.Width - 1 && AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x + 1, y))) {
pixels.Enqueue(new Point(x + 1, y));
spanR = true;
}
} else if (!AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x + 1, y))) {
spanR = false;
}
} while (++y < img.Height && AreEqual(ref oldColor, WinAPI.GetPixel(hdc2, x, y)));
} while (pixels.Count > 0);
WinAPI.BitBlockTransfer(hdc2, hdc1, 0, 0, 0, 0, img.Width, img.Height, WinAPI.TRO.SRCCOPY);
} catch {
return false;
} finally {
if (hdc2 != IntPtr.Zero)
WinAPI.DeleteDC(hdc2);
if (g != null) {
if (hdc1 != IntPtr.Zero)
g.ReleaseHdc(hdc1);
g.Dispose();
}
}
return true;
}
Jeff
|
|
|
|
|
Read my image processing articles.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Yep, that pointer implementation worked nicely. I now have four working implementations... One is with the built in GetPixel and SetPixel methods (excruciatingly slow), the second uses Win API GetPixel and SetPixel methods (as in the first post of this thread) (pretty slow), the third uses the LockBits method on the Bitmap, then I use Marshal.ReadInt32 and Marshal.WriteInt32 to modify the bitmap directly without using pointers (pretty fast), and the final way is to use int pointers and the LockBits method (blazingly fast!) The most unbeleivable part is that the pointer method is faster than the Win API ExtFloodFill method, and I even have WAY more control over how the fill is done (allowing near-matches in addition to exact matches). Thanks for the input!
Jeff
|
|
|
|
|
Hi Jeff,
for this I would stay clear from images if at all possible; a simple array should do,
you only need empty, border, and one or a few fill values.
As always, I prefer one-dimensional arrays over two-dimensional ones
(typically less code, more speed).
On the other hand, there are some CP articles on similar things such as this one.[^]
Luc Pattyn [Forum Guidelines] [My Articles]
this months tips:
- use PRE tags to preserve formatting when showing multi-line code snippets
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
Hi,
I have some problems with the updating of database. I will need to update 2 tables in one sql query and I am not too sure how to write a stored procedure with sql server. Need some guidance.
Thanks.
Regards,
Jo
|
|
|
|
|
Where are you stuck ? What does the proc look like ?
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[UpdatePAppParty]
@PID VARCHAR(10),
@AID VARCHAR(10),
@name VARCHAR(50),
@designation VARCHAR(20),
@status VARCHAR(15),
@reasons VARCHAR(100)
AS
Begin
Update [aParty eStatus]
Set names = @name, designation = @designation, status = @status, reason = @reasons
where aParty.APID = estatus.APID and aParty.projectID = estatus.projectID
END
this is the procedure that i came out with. not too sure if it is correct.
Regards,
Jo
|
|
|
|
|
That's one update statement, so just add your second statement and you're done, right ?
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
i dont get what you mean by the second statment. The statement i have is to update 2 tables.
|
|
|
|
|
Have the second update statement for the next table with the appropriate condition. Encapsulate the Update statements in a TRANSACTION block so that if an error occurs in one update, the data integrity is preserved.
|
|
|
|
|
Hi friends,
I am making runtime application,
I have buttons , I want to receive the points(coordinates) of my buttons by using foreach method. Is there any property or method to give the coordinates of any controls(button, label, ...).
|
|
|
|
|
|
Hi.
I have created a dll from C code using MinGW. I try using it in my C# code, the code compiles, but the executable always hangs. If I use the dll in plain C code, the executable runs fine. I've gone through several tutorials and the dll always hangs if I try to run my compiled C# code. For reference, the last tutorial I attempted was this one.
What am I doing wrong? How can I access a dll, compiled with gcc under MinGW, in my C# code?
|
|
|
|
|
dfn wrote: What am I doing wrong?
Hard to say if you don't post your C# calling code.
|
|
|
|
|
Hi,
How can I get, the screen resolution of user by coding.
|
|
|
|
|
Screen.PrimaryScreen
It may be Screens.PrimaryScreen.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Thanks for your quick reply,
I don't understand your answer. I want to write a code to get computer's monitor's screen resolution.For example 1024x768 pixel. When, I changed the resolution from windows's normal options, I want to see it by clicking one button for example.
|
|
|
|
|
http://msdn2.microsoft.com/en-us/library/system.windows.forms.screen.primaryscreen(VS.71).aspx[^]
Like I said, Screen.PrimaryScreen gets you access to properties of the main screen on the PC
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Oh, screen dimensions are available through the Screen class, as in
Screen.PrimaryScreen.Bounds
Luc Pattyn [Forum Guidelines] [My Articles]
this months tips:
- use PRE tags to preserve formatting when showing multi-line code snippets
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
I understood,
Thanks so much for your interest,
|
|
|
|
|
Hi,
The Graphics class has DpiX and DpiY properties, so you could capture them in an OnPaint
method.
Also the Graphics that gets created from a neutral image seems to take the current
screen's resolution, so you can do:
Bitmap bitmap=new Bitmap(100, 100);
Graphics gBM=Graphics.FromImage(bitmap);
Console.WriteLine("DpiX="+gBM.DpiX);
gBM.Dispose();
Remarks:
- on XP that setting is hidden somewhere in the Display Properties window
- by default a monitor seems to be set at 96 dpi, which does not necessaraly reflect
the real hardware's characteristics
- when you calculate it yourself, you typically get a higher number (say 120 to 148).
- if you change the Display Properties settings, you will get a bigger desktop, with
everything a lot smaller...
- I have never seen a situation where DpiX!=DpiY (which matches the fact that you can
only set one resolution, good for square pixels only)
Luc Pattyn [Forum Guidelines] [My Articles]
this months tips:
- use PRE tags to preserve formatting when showing multi-line code snippets
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
|
I'm attempting to create an application that can call .BAT files to handle tasks.
The BATCH file runs fine EXCEPT for the XCOPY call. Everyting works from a CMD window. Would .NET not allow an XCOPY execution?
Here's the code that creates the process and the calling code:
public string runProcess(string sCommand, string sArgs, bool bRedirectStandardOutput, bool bUseShellExecute)<br />
{<br />
Process seiProcess = new Process();<br />
seiProcess.StartInfo.FileName = sCommand;<br />
seiProcess.StartInfo.Arguments = sArgs;<br />
seiProcess.StartInfo.RedirectStandardOutput = bRedirectStandardOutput;<br />
seiProcess.StartInfo.UseShellExecute = bUseShellExecute; <br />
bool bStart = seiProcess.Start();<br />
<br />
if (bRedirectStandardOutput)<br />
{<br />
seiProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);<br />
seiProcess.BeginOutputReadLine();<br />
}<br />
<br />
seiProcess.WaitForExit();<br />
seiProcess.Close();<br />
return processOutput;<br />
}<br />
<br />
String r = util.runProcess(@"..\copysomething.bat", @"G d:\dvd", true, false);<br />
The batch file that is executed by the .NET app:
<br />
@ECHO OFF<br />
echo STARTING AT<br />
TIME /T<br />
xcopy %1:\* %2<br />
The above BATCH file will display the time correctly, so I know it's getting called!
Thanks in advance,
C
|
|
|
|
|
No, there's nothing in the .NET Framework that would stop XCOPY from running. Everything LOOKS fine. The problem is that the method you're using to copy the files isn't very robust and lacks any error reporting.
Can I ask why you're even bothing with XCOPY when there are native classes/methods in the .NET Framework System.Io namespace that will do the copy, and provide you with far better error reporting?
|
|
|
|
|
The structure to this process is an artifact of the solution. We need "scriptability" to allow customers to customize the actions.
What I don't understand is that the script tests fine:
D:\docs\Visual Studio 2005\Projects\RoboStation\bin>dcs-anydvd-copy.bat G d:\Temp theFolder
STARTING AT
12:53 PM
AnyDVD Window Handle: 0x0002014E
One on: 1
G:\* d:\Temp\theFolder /S /I <--proof that the parameters are working
G:\JACKET_P\J00___5L.MP2
G:\JACKET_P\J00___5M.MP2
G:\JACKET_P\J00___5S.MP2
G:\VIDEO_TS\VIDEO_TS.BUP
G:\VIDEO_TS\VIDEO_TS.IFO
G:\VIDEO_TS\VIDEO_TS.VOB
G:\VIDEO_TS\VTS_01_0.BUP
G:\VIDEO_TS\VTS_01_0.IFO
G:\VIDEO_TS\VTS_01_0.VOB...................
I know the script is called properly in terms of passing the parameters. I wonder if XCOPY needs additional enviromental settings like "Working Directory".
I will test that hypothesis.
|
|
|
|
|