c# - Faster Image Processing than Lock Bits -


i've been working on edge detection program in c#, , make run faster, made use lock bits. however, lockbits still not fast run. although problem general algorithm, i'm wondering if there better lockbits can use image processing.

in case problem algorithm, here's basic explanation. go through array of colors (made using lockbits, represent pixels) , each color, check color of 8 pixels around pixel. if pixels not match current pixel closely enough, consider current pixel edge.

here's basic code defines if pixel edge. takes in color[] of 9 colors, first of pixel check.

      public boolean isedgeoptimized(color[] colors)     {           //colors[0] should checking pixel           boolean returnbool = true;           float percentage = percentageint; //the percentage used set           //equal global variable percentageint           if (ismatching(colors[0], colors[1], percentage) &&              ismatching(colors[0], colors[2], percentage) &&              ismatching(colors[0], colors[3], percentage) &&              ismatching(colors[0], colors[4], percentage) &&              ismatching(colors[0], colors[5], percentage) &&              ismatching(colors[0], colors[6], percentage) &&              ismatching(colors[0], colors[7], percentage) &&              ismatching(colors[0], colors[8], percentage))              {                  returnbool = false;              }           return returnbool;      }  

this code applied every pixel, colors of fetched using lockbits.

so basically, question is, how can program run faster? algorithm, or there can use faster lockbits?

by way, project on github, here

are passing in floating point number percentage ismatching?

i looked @ code ismatching on github , well, yikes. ported java, right? c# uses bool not boolean , while don't know sure, don't looks of code boxing , unboxing. further, you're doing ton of floating point multiplication , comparison when don't need to:

public static bool ismatching(color a, color b, int percent) {     //this method used identify whether 2 pixels,      //of color , b match, in can considered     //a solid color based on acceptance value (percent)      int thresh = (int)(percent * 255);      return math.abs(a.r - b.r) < thresh &&            math.abs(a.g - b.g) < thresh &&            math.abs(a.b - b.b) < thresh; } 

this cut down amount of work you're doing per pixel. still don't because try avoid method calls in middle of per-pixel loop 8x per-pixel loop. made method static cut down on instance being passed in isn't used. these changes alone double performance since we're doing 1 multiply, no boxing, , using inherent short-circuit of && cut down work.

if doing this, i'd more this:

// assert: bitmap.height > 2 && bitmap.width > 2 bitmapdata data = bitmap.lockbits(new rectangle(0, 0, bitmap.width, bitmap.height),                       imagelockmode.readwrite, pixelformat.format24bpprgb);  int scaledpercent = percent * 255; unsafe {     byte* prevline = (byte*)data.scan0;     byte* currline = prevline + data.stride;     byte* nextline = currline + data.stride;      (int y=1; y < bitmap.height - 1; y++) {         byte* pp = prevline + 3;        byte* cp = currline + 3;        byte* np = nextline + 3;        (int x = 1; x < bitmap.width - 1; x++) {            if (isedgeoptimized(pp, cp, np, scaledpercent))            {                // need            }            pp += 3; cp += 3; np += 3;        }        prevline = currline;        currline = nextline;        nextline += data.stride;     } }  private unsafe static bool isedgeoptimized(byte* pp, byte* cp, byte* np, int scaledpecent) {     return ismatching(cp, pp - 3, scaledpercent) &&            ismatching(cp, pp, scaledpercent) &&            ismatching(cp, pp + 3, scaledpercent) &&            ismatching(cp, cp - 3, scaledpercent) &&            ismatching(cp, cp + 3, scaledpercent) &&            ismatching(cp, np - 3, scaledpercent) &&            ismatching(cp, np, scaledpercent) &&            ismatching(cp, np + 3, scaledpercent); }  private unsafe static bool ismatching(byte* p1, byte* p2, int thresh) {     return math.abs(p1++ - p2++) < thresh &&            math.abs(p1++ - p2++) < thresh &&            math.abs(p1 - p2) < thresh; } 

which kinds of horrible pointer mangling cut down on array accesses , on. if of pointer work makes feel uncomfortable, can allocate byte arrays prevline, currline , nextline , marshal.copy each row go.

the algorithm this: start 1 pixel in top , left , iterate on every pixel in image except outside edge (no edge conditions! yay!). keep pointers starts of each line, prevline, currline, , nextline. when start x loop, make pp, cp, np previous pixel, current pixel , next pixel. current pixel 1 care about. pp pixel directly above it, np directly below it. pass isedgeoptimized looks around cp, calling ismatching each.

now assume 24 bits per pixel. if you're looking @ 32 bits per pixel, magic 3's in there need 4's, other code doesn't change. parameterize number of bytes per pixel if want handle either.

fyi, channels in pixels typically b, g, r, (a).

colors are stored bytes in memory. actual bitmap, if 24 bit image stored block of bytes. scanlines data.stride bytes wide, @ least large 3 * number of pixels in row (it may larger because scan lines padded).

when declare variable of type byte * in c#, i'm doing few things. first, i'm saying variable contains address of location of byte in memory. second, i'm saying i'm violate safety measures in .net because read , write byte in memory, can dangerous.

so when have like:

math.abs(*p1++ - *p2++) < thresh 

what says (and long):

  1. take byte p1 points , hold onto it
  2. add 1 p1 (this ++ - makes pointer point next byte)
  3. take byte p2 points , hold onto it
  4. add 1 p2
  5. subtract step 3 step 1
  6. pass math.abs.

the reasoning behind that, historically, reading contents of byte , moving forward common operation , 1 many cpus build single operation of couple instructions pipeline single cycle or so.

when enter ismatching, p1 points pixel 1, p2 points pixel 2 , in memory laid out this:

p1    : b p1 + 1: g p1 + 2: r  p2    : b p2 + 1: g p2 + 2: r 

so ismatching the absolute difference while stepping through memory.

your follow-on question tells me don't understand pointers. that's ok - can learn them. honestly, concepts aren't hard, problem them without lot of experience, quite shoot in foot, , perhaps should consider using profiling tool on code , cooling down worst hot spots , call good.

for example, you'll note first row penultimate row , first column penultimate column. intentional avoid having handle case of "i can't read above 0th line", eliminates big class of potential bugs involve reading outside legal memory block, may benign under many runtime conditions.


Comments

Popular posts from this blog

node.js - Bad Request - node js ajax post -

Why does Ruby on Rails generate add a blank line to the end of a file? -

keyboard - Smiles and long press feature in Android -