Results 1 to 16 of 16

Thread: Quick question regarding color conversions

  1. #1
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default Quick question regarding color conversions

    I was just wondering what would be the fastest way of getting a matrix containing the colors, in 0-255 gray scale, of a given box? Currently what I have looks like this:

    Simba Code:
    two := BitmapFromClient(x1,y1,x2,y2);
    one := BitmapToMatrix(two);
    for i:=0 to high(one) do begin
      for j:=0 to high(one[0]) do begin
        one[i,j] := (ColorToGray(one[i,j]));
      end;
    end;

    I couldn't find or think of anything that seemed to improve it all, but I just wanted to ask to be sure. If there isn't a better way of doing it that's fine too, I was just hoping that I didn't have to iterate over every pixel.

  2. #2
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Polar Xpress View Post
    I was just wondering what would be the fastest way of getting a matrix containing the colors, in 0-255 gray scale, of a given box? Currently what I have looks like this:

    Simba Code:
    two := BitmapFromClient(x1,y1,x2,y2);
    one := BitmapToMatrix(two);
    for i:=0 to high(one) do begin
      for j:=0 to high(one[0]) do begin
        one[i,j] := (ColorToGray(one[i,j]));
      end;
    end;

    I couldn't find or think of anything that seemed to improve it all, but I just wanted to ask to be sure. If there isn't a better way of doing it that's fine too, I was just hoping that I didn't have to iterate over every pixel.


    You might be making a COPY of the pixels there.. BitmapToMatrix - "one", might return a copy of the pixels for BitmapFromClient - "two".

    Might be easier to do GetMufasaBitmap(two) and change the underlying pixels directly.
    I am Ggzz..
    Hackintosher

  3. #3
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    You might be making a COPY of the pixels there.. BitmapToMatrix - "one", might return a copy of the pixels for BitmapFromClient - "two".

    Might be easier to do GetMufasaBitmap(two) and change the underlying pixels directly.
    To do it in the manner you mentioned, I would still need to iterate over each pixel to get its color, convert it to gray scale, and then set the pixel to the new gray value, correct? In doing it that way, it didn't seem particularly faster, unfortunately. It did, however, help me discover the usefulness of MufasaBitmap, as it has a couple other functions I've been in need of.

  4. #4
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    Quote Originally Posted by Polar Xpress View Post
    I was just wondering what would be the fastest way of getting a matrix containing the colors, in 0-255 gray scale, of a given box? Currently what I have looks like this:

    Simba Code:
    two := BitmapFromClient(x1,y1,x2,y2);
    one := BitmapToMatrix(two);
    for i:=0 to high(one) do begin
      for j:=0 to high(one[0]) do begin
        one[i,j] := (ColorToGray(one[i,j]));
      end;
    end;

    I couldn't find or think of anything that seemed to improve it all, but I just wanted to ask to be sure. If there isn't a better way of doing it that's fine too, I was just hoping that I didn't have to iterate over every pixel.
    This looks fine to me. Nothing wrong with iterating through every point if it only takes 3 lines. The only thing that I would change is high(one[0]) to high(one[i]). It doesn't matter in this case, but it's good practice. Oh and you don't need begin end; on those for loops.

    I think Brandon is talking about changing the colors on the actual bitmap. You said you wanted a matrix though, so what you're doing is correct AFAIK. If you did want to save a bitmap you could just do drawMatrixBitmap() with what you currently have.
    You also say you want "fast." What you're doing should already be very fast.
    Last edited by Citrus; 04-29-2016 at 06:43 AM.

  5. #5
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    It is fairly fast, yes. I was getting times any where from 40-90ms, usually around 70, for a bitmap the size of the OSR main screen, which isn't too bad. There's just a number of other calculations I'd want to do on top of this, so at 70ms I think I may choose to put that time towards those other calculations to make the overall time better. I don't necessarily need to make this adjustment (I just like working with the 0-255 gray scale better), but I was hoping I could find a way to squeeze this in while having virtually no time impact. I don't think that will be the case, however.

  6. #6
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    I think you'd have to make a plugin to speed it up at this point. You might not see a major improvement though.
    see: http://docs.villavu.com/simba/simbaref/plugins.html

  7. #7
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    Yeah, I was thinking that might be the case. Even if it doesn't end up with much of a performance increase, I haven't created a plug-in for simba before so I could always use it as a learning experience and still come away with that at least.

  8. #8
    Join Date
    Feb 2012
    Location
    Norway
    Posts
    995
    Mentioned
    145 Post(s)
    Quoted
    596 Post(s)

    Default

    Quote Originally Posted by Polar Xpress View Post
    Yeah, I was thinking that might be the case. Even if it doesn't end up with much of a performance increase, I haven't created a plug-in for simba before so I could always use it as a learning experience and still come away with that at least.
    With a proper implementation I would expect at least a 10x speedup for what you are doing.

    I am curious as to what you are actually doing tho. Care to tell us?
    Last edited by slacky; 04-29-2016 at 08:56 AM.
    !No priv. messages please

  9. #9
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    Quote Originally Posted by slacky View Post
    With a proper implementation I would expect at least a 10x speedup for what you are doing.

    I am curious as to what you are actually doing tho. Care to tell us?
    10x speed up would be perfect. As for what I'm doing, I'm more or less just messing around with some various feature detections, like SIFT, to see if I can get any of them to be fast enough to be used in real time, but still robust enough to be useful. However, in implementing them so far, they've all been a bit too slow, or I've had to simplify them to the point that they just aren't even useful anymore. I was trying to see if I could make improvements to cut down the time, but I'm thinking that ultimately I may need to put most of the work into plug-ins. I figure that since it doesn't look like I can speed this up in Simba itself, it's likely that I can't find too many ways to speed up the rest of it either so learning to make a plug-in do something simple like this could be a good way to start the process. Even if I don't get it working the way I would like, it's just a little project to keep me busy.
    Last edited by Polar Xpress; 05-03-2016 at 03:48 PM.

  10. #10
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    @slacky is right as always
    Progress Report by Citrus:
    pixels: 16777216
    normal: 1560 ms
    plugin: 109 ms

    more than 10x faster for a large image.

    With the RS3 client (480000 pixels) the times were 47 and 0 ms.

    Here are the images.
    Last edited by Citrus; 04-29-2016 at 07:41 PM.

  11. #11
    Join Date
    Jan 2012
    Posts
    1,596
    Mentioned
    78 Post(s)
    Quoted
    826 Post(s)

    Default

    I think the real question is... Does it have to be simba? If its not RS related and simply image processing, there are other programs that can probably do this (and the included matrix ops) faster.
    Like matlab.

  12. #12
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Polar Xpress View Post
    To do it in the manner you mentioned, I would still need to iterate over each pixel to get its color, convert it to gray scale, and then set the pixel to the new gray value, correct? In doing it that way, it didn't seem particularly faster, unfortunately. It did, however, help me discover the usefulness of MufasaBitmap, as it has a couple other functions I've been in need of.
    I gave a hint (the idea was for you to look into TMufasaBitmap and explore it -- You seemed eager to learn so I didn't want to post a full on answer). Anyway, here's how to do it with Simba's internals (just as fast as a plugin).

    Simba Code:
    function grayScale: Integer;
    var
      Area: TBox;
      Bmp: TMufasaBitmap;
    begin
      GetClientDimensions(Area.X2, Area.Y2);
      Bmp := GetMufasaBitmap(BitmapFromClient(Area.X1, Area.Y1, Area.X2 - 1, Area.Y2 - 1));
      Bmp.GreyScale();
      Result := Bmp.getIndex;

      //DisplayDebugImgWindow(Area.X2 - 1, Area.Y2 - 1);
      //DrawBitmapDebugImg(Result);
    end;


    var
      Bmp: Integer;
    begin
      Bmp := GrayScale;
      FreeBitmap(Bmp);
    end.


    Even with iteration.. it'd still be faster than what you have because what I said does not make a matrix COPY of the bitmap's pixels and modifies it. It just modifies the already existing bitmap's underlying pixels.. For even more speed, you could also use the bitmap's pointer to the pixels and change it to gray as well. None of these options allocate extra memory.

    All three options are faster. Unfortunately I don't have time to write you the example via Pointer. These two examples should be more than enough to get you started. (Note: the first example is faster).

    Simba Code:
    function grayScale: Integer;
    var
      I, J: Integer;
      Area: TBox;
      Bmp: TMufasaBitmap;
    begin
      GetClientDimensions(Area.X2, Area.Y2);
      Bmp := GetMufasaBitmap(BitmapFromClient(Area.X1, Area.Y1, Area.X2 - 1, Area.Y2 - 1));

      for I := 0 to Area.X2 - 1 do
        for J := 0 to Area.Y2 - 1 do
          Bmp.SetPixel(I, J, ColorToGray(Bmp.GetPixel(I, J))); //ColorToGray returns byte.

      Result := Bmp.getIndex;

      //DisplayDebugImgWindow(Area.X2 - 1, Area.Y2 - 1);
      //DrawBitmapDebugImg(Result);
    end;


    var
      Bmp: Integer;
    begin
      Bmp := GrayScale;
      FreeBitmap(Bmp);
    end.

    @Wizzup?; ColorToGray seems to be red-scaling/red-tinting the bitmap.
    Last edited by Brandon; 05-01-2016 at 08:50 PM.
    I am Ggzz..
    Hackintosher

  13. #13
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    ColorToGray seems to be red-scaling/red-tinting the bitmap.
    You probably know this, but grayscale is a single value 0-255. To get back to RGB you use that number three times.
    e.g. grayscale = 120
    RGB = (120, 120, 120)
    There is no reason for ColorToGray to convert color --> grayscale --> back to color.

    e: I added an image to the album that shows the red-scaling you were talking about.

    For those who don't know how decimal numbers (0-16777215 = black to white) represent colors in Simba:
    You can think of it like the odometer in your car. There are usually 6 columns, each with a wheel labeled 0-9. Every mile, the 'one' column increases. After 10 miles, the 'ten' column increases by one and the 'one' column resets back to 0.

    RGB colors are like a 3-column meter with 0-255 in each column (they are ordered backward - BGR). Each tick adds to the 'red' column until it gets to 255, then the 'green' colums increases by one. It's much easier to think about in hexadecimal

    Blue Green Red
    (000, 000, 000) = 0 (pure black)
    (000, 000, 001) = 1
    (000, 000, 002) = 2
    ...
    (000, 000, 255) = 255 (pure red)
    (000, 001, 000) = 256
    (000, 001, 001) = 257
    ...
    (255, 255, 255) = 16777215 (pure white)

    This image is every color (0-16777215) in order, left to right and top to bottom. If you zoom way in you can see what I'm talking about.
    Last edited by Citrus; 05-01-2016 at 09:10 PM.

  14. #14
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Citrus View Post
    ..
    Definitely didn't check to see that it returns a byte.. I know what grayscale is but this is a difference between expectation and reality. I give it a colour, I expect a colour back.

    ColorToGray does the average of the 3 channels and returns a single byte. So if I were to make the above code work, I'd have to apply the result of ColorToGray to all 3 channels (as you pointed out).

    Instead, I now have to do:

    Simba Code:
    Colour := ColorToGray(Bmp.GetPixel(I, J));
    Bmp.SetPixel(I, J, RGBToColor(Colour, Colour, Colour));

    If you never bothered to look at the implementation of ColorToGray or the function signature, you'd get exactly what happened to me in the previous post.

    Take a look at OP's post. He doesn't realize that ColorToGray returns a byte either.. He's replacing all the actual colours (3 bytes) in his matrix with a single byte. He too expects it to return a fully formed colour.

    Simba Code:
    one[i,j] := ColorToGray(one[i,j]); //OP expects a colour to be returned..


    And +1 for seeing that it returns a byte.
    Last edited by Brandon; 05-01-2016 at 09:13 PM.
    I am Ggzz..
    Hackintosher

  15. #15
    Join Date
    Feb 2012
    Location
    Norway
    Posts
    995
    Mentioned
    145 Post(s)
    Quoted
    596 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Take a look at OP's post. He doesn't realize that ColorToGray returns a byte either.. He's replacing all the actual colours (3 bytes) in his matrix with a single byte. He too expects it to return a fully formed colour.

    Simba Code:
    one[i,j] := ColorToGray(one[i,j]); //OP expects a colour to be returned..
    Assumptions, assumptions :b He may not store it in a byte matrix, but that doesn't mean the goal is to have it represent a 3 or 4 channel image (he doesn't store it in a BGR(A) matrix either). All he needs is an intensity representation of the image (considering he is implementing the SIFT algorithm, iirc). I do however think he can use im.GrayScale for what he is doing, but, I doubt he'd see much performance gain by doing that, overall, this is not where most of the time is spent.

    Perhaps, he should forget about performance (as much as possible), leave most optimizations till the end. And once it's completed he can move it all to a plugin, where he can do whatever finalizing adjustments needed. SIFT is by no means quick to compute, so I think placing everything in a plugin would be much needed no matter. I still doubt it would be fast at that point, it's quite computational expensive, but maybe not useless.
    Last edited by slacky; 05-02-2016 at 03:58 AM.
    !No priv. messages please

  16. #16
    Join Date
    Apr 2015
    Location
    Pittsburgh
    Posts
    14
    Mentioned
    0 Post(s)
    Quoted
    7 Post(s)

    Default

    My apologies for the silence over the past few days. I ended up getting mistakenly labeled as a spammer so I wasn't able to make any posts.

    Anyways, I ended up using some bitwise shifting to get an approximation of the gray scale value that, for all intents and purposes, worked just fine. I could have just used the MufasaBitmap's GreyScale function as was mentioned, but the values returned, while they were gray, were not in the 0-255 scale that I mentioned I would have preferred. The reasoning behind this preference is just the fact that I have grown comfortable using that intensity scale while doing similar work with Matlab.

    However, after getting a slightly modified version of SIFT implemented, it didn't quite live up to expectations so I'm not sure if I'm going to pursue turning it into a plugin just yet or what my plans are for it moving forward. I think I might just experiment with other approaches so I can make some comparisons and see what results I like better. Regardless, I wanted to thank you all for your help on the matter.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •