The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   OS X Developer (http://hintsforums.macworld.com/forumdisplay.php?f=27)
-   -   NSImage and getting access into each pixel (http://hintsforums.macworld.com/showthread.php?t=112729)

maverick 07-09-2010 08:30 AM

NSImage and getting access into each pixel
 
Hi,
I'm writing an app that's operating on images (only black and white). Image is in .jpg format.
First of all image is NSImage object. Then it's passed to method that should operate on pixels of that image. And here I've a problem. I haven't found a good example on the internet to understand what to do. So i made it myself but... it's not working.

I have this method which is receiving an object:

Code:

- (NSImage *)skeletonization: (NSImage *)image
{
        NSImage *workingImage = image;
        NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithData:[workingImage TIFFRepresentation]];
       
        NSImage *producedImage = [NSImage alloc];
        [producedImage addRepresentation:bitmapImageRep];
       
        return producedImage;
}

And then in main method I have:

Code:

- (IBAction)button1: (id)sender
{
        NSImage *myImage = [NSImage imageNamed:@"finger1.jpg"];
       
        // Here I'm passing object to a method
        NSImage *newImage = [self skeletonization:myImage];
       
        [oryginalImage setImage:myImage];

        // Here image should be displayed in NSImageView
        [skeletonizedImages setImage:newImage];
        [imageWidth setIntValue:myImage.size.width];
        [imageHeight setIntValue:myImage.size.height];
}

But after "Save&Play", and pressing a button i recieve this:
Program received signal: “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all
kill
quit


Does anybody know where is problem?

regulus6633 07-09-2010 10:18 AM

Try this.
1) producedImage... you have to init it also.
2) you don't need "workingImage"
3) be careful of memory management. Any time you "alloc" something you are responsible for releasing it.
Code:

- (NSImage *)skeletonization: (NSImage *)image
{
        NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];
       
        NSImage *producedImage = [[NSImage alloc] init];
        [producedImage addRepresentation:bitmapImageRep];
        [bitmapImageRep release];
        return [producedImage autorelease];
}


maverick 07-09-2010 02:04 PM

Thank you. init and memory menagement was the problem.
I have one more question. How to get access to rows and columns? Do I have to make an array or there is a specific method (like: unsigned char *pixelData = [imageRep bitmapData])? Maybe I've misted something in documentation...

regulus6633 07-09-2010 03:01 PM

If you want to access the individual pixel data, you do that with your bitmapImageRep. NSBitmapImageRep has this method... getPixel:atX:y:. So it's already in rows/columns for you. There's also colorAtX:y: to get the color values.

maverick 07-14-2010 07:50 AM

I have read about getPixel:atX:y and setColor:atX:y: but i can't figure it out how this methods work. I mean first i have to get pixel?and then setColor of this pixel? I feel like running around without a reason :/

To get to each pixel of my image i'm using 2 loops:
Code:

NSColor *myColor = [[NSColor alloc] init];

// I'm not sure next line
[myColor set:blueColor];
       
for (x=1; x<=[bitmapImageRep pixelsWide]; x++) {
        for (y=1; y<=[bitmapImageRep pixelsHigh]; y++) {
                [bitmapImageRep setColor:myColor atX:x y:y];
        }
}

App works, no error or warning is being displayed but nothing happens - pixels are not changing their colors. Debugger console just says:
*** -colorSpaceName not defined for the NSColor <NSColor: 0x1001559e0>; need to first convert colorspace.

hayne 07-14-2010 08:47 AM

Have you read this:
http://developer.apple.com/mac/libra...DrawColor.html

maverick 07-14-2010 10:38 AM

No i have not. Man this framework is huge :/ When you think that you have read all documents there's always something more. But thanks ;)

Mikey-San 07-14-2010 05:32 PM

A color is meaningless without a model to describe how the color's values should be rendered. That's what a color space is. An analogue is a string being only half of the equation: you need to know more information about the string (its encoding) in order to interpret it correctly.

You're alloc/init'ing an NSColor object directly, and that's generally not something you want to do. Use the methods in the NSColor class documentation to create color objects instead so their attributes (e.g., color space) are given significant values.

edit:

And this doesn't make sense on two levels:

Code:

[myColor set:blueColor];
1. Assuming you don't have some kind of custom category, -set: is not a method on NSColor; -set is a real method, and it's used to set the receiver as the current drawing color in the current graphics context.

2. Assuming it worked at all, if you have a blue color object already, why not just reuse it?

Mikey-San 07-14-2010 05:50 PM

One More Thing™

Don't forget about the cocoa-dev mailing list, which tackles these kinds of questions all the time. (Read the docs, then search the list, then post if you haven't found the answer.)

maverick 07-16-2010 07:36 AM

Hi again. I have a another question. Well I've finally made a program that changes pixel. And it wasn't so hard to write ;) But NSImage/NSBitmapImageRep is a bit slow. It takes at least 2 sec to change all pixels in picture (which, actually are not so big). And it's only a part of my algorithm. So I changed NSBitmapImageRep to CGImageRef. And it's working. But i still need to get into each pixel (skeletonization algorithm) ;) I read on the dev apple site that I need to create bitmap context. And here is my question before I start digging into CGImage - what is better ? What is fast enough? Is it better stay with CGImage or start somewhere else?

hayne 07-16-2010 10:25 AM

I reiterate what Mikey-San said above - the cocoa-dev mailing list is a better venue for such questions. And I think you will find that similar questions to yours have been discusses already - see the list archives.

maverick 07-16-2010 10:30 AM

Yes i searched archives of this mailing list but without result. So i posted here. Now i only need to subscribe this mailing list...

hayne 07-16-2010 11:08 AM

I think you need to broaden your search terms. E.g. look for discussions of speeding up graphics drawing.

And I assume that you know about (and are using) Instruments and Shark.

maverick 07-16-2010 11:51 AM

I know about this. But now I'm not using.

hayne 07-16-2010 12:23 PM

Quote:

Originally Posted by maverick (Post 590039)
But now I'm not using.

If you have a problem with speed of execution, you should start by profiling your code with those tools.

maverick 07-20-2010 07:24 AM

Still one thing is on my mind in method getPixel:atX:y:. What should I pass as (NSUInteger [])p? I want to get some informations about picture and x,y coordinates are clear. But not (NSUInteger [])p. ;)

hayne 07-20-2010 07:25 PM

It would seem from that declaration that you are supposed to pass it the address of an NSUInteger array (of an appropriate size) and it will fill in that array.

maverick 07-24-2010 06:33 AM

Ok I changed my program, and now using CoreGraphic and graphics context. Doing as documentation says. I have a method:

Code:

- (NSImage *)skeletonization: (NSImage *)image
{
        NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];
        int width = [bitmapImageRep pixelsWide];
        int height = [bitmapImageRep pixelsHigh];
       
        CGRect myBox;
        myBox = CGRectMake(0, 0, width, height);
       
        CGContextRef myBitmapContext = MyCreateBitmapContext(width, height);
       
        [bitmapImageRep release];
       
        CGImageRef myImage = CGBitmapContextCreateImage(myBitmapContext);
        NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:myImage];

        NSImage *producedImage = [[NSImage alloc] init];
        [producedImage addRepresentation:bitmapRep];
       
        [bitmapRep release];
        CGContextRelease(myBitmapContext);
        CGImageRelease(myImage);
       
        return [producedImage autorelease];
}

and routine to create graphics context:

Code:

CGContextRef MyCreateBitmapContext (int pixelsWide, int pixelsHigh)
{
        CGContextRef myContext = NULL;
        CGColorSpaceRef myColorSpace;
        void *bitmapData;
        int bitmapByteCount;
        int bitmapBytesPerRow;
       
        bitmapBytesPerRow = (pixelsWide * 4);
        bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
       
        myColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
       
        bitmapData  = malloc(bitmapByteCount);
       
        if (bitmapData == NULL) {
                fprintf(stderr, "Memory not Allocated");
                return NULL;
        }
       
        myContext = CGBitmapContextCreate(bitmapData,
                                                                          pixelsWide,
                                                                          pixelsHigh,
                                                                          8,
                                                                          bitmapBytesPerRow,
                                                                          myColorSpace,
                                                                          kCGImageAlphaNone);
        if (myContext == NULL) {
                free(bitmapData);
                fprintf(stderr, "myContext not created");
                return NULL;
        }
       
        CGColorSpaceRelease(myColorSpace);
       
        return myContext;
}

So still I want to redraw image to second NSImageView. After running this method, second NSImageView is being colored black. But I don't know why. I don't see any errors, and all code is made with Apple's guide in my hand.

hayne 07-24-2010 10:07 AM

I'm not at all familiar with CG but looking at the data flow in your "skeletonization" method, I don't see anywhere that you are copying the image data.

maverick 07-24-2010 01:19 PM

Could you say why I need to do that? Because I thought all I need is to create image from JPG or bitmap context (which I did by CGImageRef myImage = CGBitmapContextCreateImage(myBitmapContext); ).

hayne 07-24-2010 03:04 PM

Just follow the trail of data in your variables:

image -> bitmapImageRep -> width, height -> myBitmapContext -> myImage -> bitmapRep -> producedImage

You see that the only thing you take from the original image is its width & height. No where do you refer to the data in the image.

Clearly you need to do a lot more reading. Maybe google for more examples, or download open source programs that might be doing similar things, etc.


All times are GMT -5. The time now is 06:23 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.