cut strech new Bitmap

  • Hello

    I am doing some experiments on character recognition.
    The idea is to cut out characters from an image, stretch the characters so they fit the input of an neural network.

    I have problems to do the cutting shrinking in an efficient way.

    The source image (containing all writing) is currently a bitmap.
    A rect defines which area shall be cut out (the charater)
    Then I create a new bitmap which the source draws the cut out into, with stretching.

    + (NSBitmapImageRep *) createCharacterImage:(NSBitmapImageRep *)image rect:(NSRect)rect {
        NSBitmapImageRep *targetBitmapRep;
        NSRect targetRect = NSMakeRect(0, 0, rect.size.width, rect.size.height);

        NSImage *scaledImage = [[NSImage alloc] initWithSize: targetSize];
        [sourceImage addRepresentation:image];

        [image lockFocus];
        targetBitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:targetRect];
        [image unlockFocus];

        NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:targetBitmapRep];
        [NSGraphicsContext saveGraphicsState];
        [NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
        [image drawInRect:targetRect fromRect:rect operation:NSCompositeCopy fraction:1.0];
        [image drawInRect:]
        [NSGraphicsContext restoreGraphicsState];

        return targetBitmapRep;
    }

    All the hazel of going from bitmap -> to image (used for drawInRect)
    Is there another way of creating the new bitmap (targetBitmapRep?

    A side note: I only use bitmaps because it is so easy to get all pixel values from x y coordinates, which are then later put into the neural network.

    Suggestions are very welcome.
    THX
  • On 3 Dec 2007, at 13:04, <s5804...> wrote:

    > + (NSBitmapImageRep *) createCharacterImage:(NSBitmapImageRep
    > *)image rect:(NSRect)rect {
    > NSBitmapImageRep *targetBitmapRep;
    > NSRect targetRect = NSMakeRect(0, 0, rect.size.width,
    > rect.size.height);
    >
    > NSImage *scaledImage = [[NSImage alloc] initWithSize: targetSize];
    > [sourceImage addRepresentation:image];
    >
    > [image lockFocus];
    > targetBitmapRep = [[NSBitmapImageRep alloc]
    > initWithFocusedViewRect:targetRect];
    > [image unlockFocus];
    >
    > NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext
    > graphicsContextWithBitmapImageRep:targetBitmapRep];
    > [NSGraphicsContext saveGraphicsState];
    > [NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
    > [image drawInRect:targetRect fromRect:rect
    > operation:NSCompositeCopy fraction:1.0];
    > [image drawInRect:]
    > [NSGraphicsContext restoreGraphicsState];
    >
    > return targetBitmapRep;
    > }

    There seems to be a lot of unnecessary rubbish in your function, which
    is probably why it's slow.  Here's a shorter version:

    + (NSBitmapImageRep *)characterImage:(NSImage *)image inRect:
    (NSRect)rect
    {
      NSRect targetRect = { NSZeroPoint, targetSize };
      NSBitmapImageRep  *result = [[[NSBitmapImageRep alloc]
    initWithBitmapDataPlanes:NULL
                                    pixelsWide:ceil(NSWidth(targetRect))
                                    pixelsHigh:ceil(NSHeight(targetRect))
                                    bitsPerSample:8
                                    samplesPerPixel:4
                                    hasAlpha:YES
                                    isPlanar:NO

    colorSpaceName:NSCalibratedRGBColorSpace
                                    bitmapFormat:0
                                    bytesPerRow:0
                                    pixelBits:0] autorelease];

      NSGraphicsContext *gc = [NSGraphicsContext
    graphicsContextWithBitmapImageRep:result];
      [NSGraphicsContext saveGraphicsState];
      [NSGraphicsContext setCurrentContext:gc];
      [image drawInRect:targetRect fromRect:rect
    operation:NSCompositeCopy fraction:1.0];
      [NSGraphicsContext restoreGraphicsState];

      return result;
    }

    Note that I'm assuming that you have an NSSize variable called
    "targetSize" that says how large you want the NSBitmapImageRep to be.
    I've also assumed that you want premultiplied RGBA data with eight
    bits per channel.  You might want to change that, I don't know.

    Additionally, I've assumed that the source image is in an NSImage,
    because the NSImageRep class doesn't provide a way to scale just part
    of the image.  You could still use NSImageRep, but if you do so you'd
    need to calculate the necessary rectangle co-ordinates to achieve the
    scaling *and* clipping that you require.

    The usual warning goes with this code; it was typed in Mail.app, and
    probably doesn't work.

    One other comment: I'm not sure whether this is really the right
    approach for the application you're talking about.  Firstly, I'm not
    convinced that splitting the image up into lots of little bitmaps is
    going to work very well (since you're going to end up misaligned) and
    second I'm not sure that relying on the system's scaling to
    appropriately sample the input pixels is necessarily the best thing to
    do here.  You may find that you need rather more control, in which
    case, particularly if your network has a fairly small input layer, you
    may be better off sampling the original image yourself (which will
    give you a lot more control over how you do the sampling anyway).

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • yep the code performs up to 50 times faster compared to my initial attempt.
    Also it was a great way of starting to get familiar with the API.

    Memory question to the code in previous post.
    The newly created NSBitmapImageRep is autorelease. Therefore it looks like all memory management requirements are take care of.

    The app idea I am playing with has really simple requirements. The letters are machine written, however the since can vary a little bit. And for simplicity the rows are perfectly aligned. My intention was to check out the built in streching/schrinking to start with.

    THX
  • On 4 Dec 2007, at 14:47, <s5804...> wrote:

    > yep the code performs up to 50 times faster compared to my initial
    > attempt.
    > Also it was a great way of starting to get familiar with the API.
    >
    > Memory question to the code in previous post.
    > The newly created NSBitmapImageRep is autorelease. Therefore it
    > looks like all memory management requirements are take care of.

    Unless I made a mistake, yes, I think that's correct.  However:

    1. If you want to keep one of the generated NSBitmapImageRep objects
    after you've finished processing the current event, you should -retain
    it and then -release it when you're done.

    2. If you are calling this method in a loop, you *might* need to think
    about creating your own autorelease pool and periodically emptying it;
    otherwise you'll continue to use-up memory during the loop and it will
    only be released when you get back to the application's run loop.

    > The app idea I am playing with has really simple requirements. The
    > letters are machine written, however the since can vary a little
    > bit. And for simplicity the rows are perfectly aligned. My intention
    > was to check out the built in streching/schrinking to start with.

    Sure.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • Thanks for pointing out the need for using retain, and make nested autorelease pools.

    My app will keep some image objects for later usage. And also many images are created in loops.
    Very conveniently I could verify this in the ADC documentation.

    http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/index.
    html?http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/C
    oncepts/AutoreleasePools.html


    "Cocoa?s ownership policy specifies that received objects should remain valid throughout the scope of the calling method"

    "If you write a loop that creates many temporary objects, you may create an autorelease pool inside the loop to dispose of those objects before the next iteration. This can help reduce the maximum memory footprint of the application."

    > 1. If you want to keep one of the generated NSBitmapImageRep objects
    > after you've finished processing the current event, you should -retain
    > it and then -release it when you're done.
    >
    > 2. If you are calling this method in a loop, you *might* need to think
    > about creating your own autorelease pool and periodically emptying it;
    > otherwise you'll continue to use-up memory during the loop and it will
    > only be released when you get back to the application's run loop.
    >
    > Kind regards,
    >
    > Alastair.
    >
    > --
    > http://alastairs-place.net
    >
    >
    >
    >
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today