objective-c - 分析由NSAffineTransform和CILineOverlay过滤器产生的位图

标签 objective-c cocoa quartz-graphics

我试图使用CIFilters链来处理图像,然后检查结果图像(位图)的每个字节。从长远来看,我不需要显示结果图像(位图)-我只需要在内存中“分析”它即可。但是近期我将其显示在屏幕上,以帮助调试。

我有一些“位图检查”代码,可以在检查我用作输入的NSImage(位图表示形式)(从JPG文件加载到NSImage)中时按预期工作。当我在下面的代码生成的outputBitmap上使用它时,它有时会按预期工作。更具体地说,当我使用NSAffineTransform过滤器创建outputBitmap时,则outputBitmap包含了我期望的数据。但是,如果我使用CILineOverlay过滤器创建outputBitmap,则位图中的所有字节中都没有任何数据。我相信这两个过滤器都能按预期工作,因为当我在屏幕上显示其结果(通过outputImageView)时,它们看起来“正确”。但是,当我检查outputBitmaps时,从CILineOverlay过滤器创建的一个为“空”,而从NSAffineTransfer创建的一个包含数据。此外,如果我将两个筛选器链接在一起,则最后运行AffineTransform时,最终的位图似乎仅包含数据。对我来说似乎很奇怪???

我的理解(通过阅读CI编程指南)是CIImage应该被视为“图像配方”而不是实际图像,因为在“绘制”图像之前,实际上不会创建该图像。鉴于此,CIimage位图没有数据是有道理的-但我不明白为什么在运行NSAffineTransform后它却有数据,但在运行CILineOverlay变换后却没有数据?基本上,我试图确定从CIImage(myResult)创建NSCIImageRep(在下面的代码中为IR)是否等效于“绘制” CIImage-换句话说,是否应该强制填充位图?如果有人知道答案,请告诉我-这将节省我几个小时的反复试验!

最后,如果答案是“必须绘制图形上下文”,那么我还有另一个问题:我是否需要按照Quartz 2D编程指南:图形上下文中的说明进行操作,清单2- 7和2-8:绘制到位图图形上下文?这就是我要走的路...但是似乎有很多代码只是强制将位图数据转储到我可以获取的数组中。因此,如果有更简便或更好的方法,请告诉我。我只想将数据(应该是)放在myResult中,并将其放入一个位图数组中,可以在其中以字节级别访问它。而且,由于我已经具有与NSBitmapImageRep一起使用的代码,除非出于某种原因(对我而言不容易理解),否则这样做不是一个好主意,因此,我宁愿将myResult转换为NSBitmapImageRep。

CIImage * myResult = [transform valueForKey:@"outputImage"]; 
NSImage *outputImage;
NSCIImageRep *ir = [NSCIImageRep alloc];
ir = [NSCIImageRep imageRepWithCIImage:myResult];
outputImage = [[[NSImage alloc] initWithSize:
                              NSMakeSize(inputImage.size.width, inputImage.size.height)]
                             autorelease];
                    [outputImage addRepresentation:ir];
[outputImageView setImage: outputImage];
NSBitmapImageRep *outputBitmap = [[NSBitmapImageRep alloc] initWithCIImage: myResult];


谢谢,
亚当

编辑#1-Peter H.评论:
访问位图数据的示例代码...

for (row = 0; row < heightInPixels; row++)
  for (column = 0; column < widthInPixels; column++) {
    if (row == 1340) {  //just check this one row, that I know what to expect
        NSLog(@"Row 1340 column %d pixel redByte of pixel is %d",column,thisPixel->redByte);
    }
}


上面的结果(所有列都包含相同的零/空值,这就是我所说的“空”)...

2010-06-13 10:39:07.765 ImageTransform[5582:a0f] Row 1340 column 1664 pixel redByte of pixel is 0
2010-06-13 10:39:07.765 ImageTransform[5582:a0f] Row 1340 column 1665 pixel redByte of pixel is 0
2010-06-13 10:39:07.766 ImageTransform[5582:a0f] Row 1340 column 1666 pixel redByte of pixel is 0


如果我将%d更改为%h,则什么都不会打印(空白而不是“ 0”)。如果将其更改为%@,则每行都会显示“(null)”,而不是上面显示的“ 0”。另一方面...当我只运行NSAffineTransform过滤器,然后执行此代码时,打印的字节包含我期望的数据(无论我如何格式化NSLog输出,都会打印出一些内容)。

在6/14上添加更多代码...

// prior code retrieves JPG image from disk and loads into NSImage
CIImage * inputCIimage = [[CIImage alloc] initWithBitmapImageRep:inputBitmap];
if (inputCIimage == nil) {
  NSLog(@"Bailing out.  Could not create CI Image");
  return;
}
NSLog (@"CI Image created.  working on transforms...");


旋转图像的过滤器...。这以前是在方法中,但是自那以后,由于我一直试图找出问题所在,因此我将其移动为“在线”。

// rotate imageIn by degreesToRotate, using an AffineTransform      
CIFilter *transform = [CIFilter filterWithName:@"CIAffineTransform"];
[transform setDefaults];
[transform setValue:inputCIimage forKey:@"inputImage"];
NSAffineTransform *affineTransform = [NSAffineTransform transform];
[affineTransform transformPoint: NSMakePoint(inputImage.size.width/2, inputImage.size.height / 2)]; 
//inputImage.size.width /2.0,inputImage.size.height /2.0)];
[affineTransform rotateByDegrees:3.75];
[transform setValue:affineTransform forKey:@"inputTransform"];
CIImage * myResult2 = [transform valueForKey:@"outputImage"]; 


过滤以应用CILineOverlay过滤器...(以前也在方法中)

CIFilter *lineOverlay = [CIFilter filterWithName:@"CILineOverlay"];
[lineOverlay setDefaults];
[lineOverlay setValue: inputCIimage forKey:@"inputImage"];
// start off with default values, then tweak the ones needed to achieve desired results
[lineOverlay setValue: [NSNumber numberWithFloat: .07] forKey:@"inputNRNoiseLevel"]; //.07 (0-1)
[lineOverlay setValue: [NSNumber numberWithFloat: .71] forKey:@"inputNRSharpness"]; //.71 (0-2)
[lineOverlay setValue: [NSNumber numberWithFloat: 1] forKey:@"inputEdgeIntensity"]; //1 (0-200)
[lineOverlay setValue: [NSNumber numberWithFloat: .1] forKey:@"inputThreshold"]; //.1 (0-1)
[lineOverlay setValue: [NSNumber numberWithFloat: 50] forKey:@"inputContrast"]; //50 (.25-200)
CIImage *myResult2 = [lineOverlay valueForKey:@"outputImage"];  //apply the filter to the CIImage object and return it


最后...使用结果的代码...

if (myResult2 == Nil)
    NSLog(@"Transformations failed");
else {
NSLog(@"Finished transformations successfully ... now render final image");
// make an NSImage from the CIImage (to display it, during initial development)
NSImage *outputImage;
NSCIImageRep *ir = [NSCIImageRep alloc];
// show the tranformed output on screen...
ir = [NSCIImageRep imageRepWithCIImage:myResult2];
outputImage = [[[NSImage alloc] initWithSize:
              NSMakeSize(inputImage.size.width, inputImage.size.height)]
             autorelease];
[outputImage addRepresentation:ir];
[outputImageView setImage: outputImage];  //rotatedImage


此时,无论我应用哪种变换以及我留下注释的变换,变换后的图像都能在屏幕上很好地显示。如果我将转换“链接”在一起,使#1的输出进入#2,它甚至可以正常工作。因此,对我来说,这似乎表明过滤器正在运行。

但是,我真正需要使用的代码是“位图分析”代码,该代码正在检查Results2中(或应该是)Result2中的位图。该代码仅适用于CIAffineTransform过滤器产生的位图。当我使用它检查由CILineOverlay生成的位图时,整个位图似乎只包含零。

这是用于该分析的代码...

// this is the next line after the [outputImageView ...] shown above
[self findLeftEdge :myResult2];


这是来自findLeftEdge方法的代码...

- (void) findLeftEdge :(CIImage*)imageInCI {
    // find the left edge of the input image, assuming it will be the first non-white pixel
    // because we have already applied the Threshold filter

    NSBitmapImageRep *outputBitmap = [[NSBitmapImageRep alloc] initWithCIImage: imageInCI];
    if (outputBitmap == nil)
        NSLog(@"unable to create outputBitmap");
    else 
        NSLog(@"ouputBitmap image rep created -- samples per pixel = %d", [outputBitmap samplesPerPixel]);

    RGBAPixel 
        *thisPixel, 
        *bitmapPixels = (RGBAPixel *)[outputBitmap bitmapData];  

    int 
    row, 
    column,
    widthInPixels = [outputBitmap pixelsWide], 
    heightInPixels = [outputBitmap pixelsHigh];

    //RGBAPixel *leftEdge [heightInPixels];
    struct { 
        int pixelNumber;
        unsigned char pixelValue;
    } leftEdge[heightInPixels];

    // Is this necessary, or does objective-c always intialize it to zero, for me?
    for (row = 0; row < heightInPixels; row++) {
        leftEdge[row].pixelNumber = 0;
        leftEdge[row].pixelValue = 0;
    }

    for (row = 0; row < heightInPixels; row++)
        for (column = 0; column < widthInPixels; column++)  {
            thisPixel = (&bitmapPixels[((widthInPixels * row) + column)]);

            //red is as good as any channel, for this test (assume threshold filter already applied)
            //this should "save" the column number of the first non-white pixel encountered
            if (leftEdge[row].pixelValue < thisPixel->redByte) {
                leftEdge[row].pixelValue = thisPixel->redByte;  
                leftEdge[row].pixelNumber = column;
            }
            // For debugging, display contents of each pixel
            //NSLog(@"Row %d column %d pixel redByte of pixel is %@",row,column,thisPixel->redByte);
            // For debugging, display contents of each pixel on one row
            //if (row == 1340) {
            //  NSLog(@"Row 1340 column %d pixel redByte of pixel is %@",column,thisPixel->redByte);
            //}

        }

    // For debugging, display the left edge that we discovered
    for (row = 0; row < heightInPixels; row++) {
        NSLog(@"Left edge on row %d was at pixel #%d", row, leftEdge[row].pixelNumber);
    }

    [outputBitmap release];  
}


这是另一个过滤器。当我使用它时,我确实会在“输出位图”中获取数据(就像“旋转”滤镜一样)。因此,只是AffineTransform无法在生成的位图中为我提供其数据...

- (CIImage*) applyCropToCI:(CIImage*) imageIn {
rectToCrop { 
    // crop the rectangle specified from the input image
    CIFilter *crop = [CIFilter filterWithName:@"CICrop"];
    [crop setDefaults];  
    [crop setValue:imageIn forKey:@"inputImage"];
//  [crop setValue:rectToCrop forKey:@"inputRectangle"];  //vector defaults to 0,0,300,300
    //CIImage * myResult = [transform valueForKey:@"outputImage"]; //this is the way it was "in-line", before putting this code into a method
    return [crop valueForKey:@"outputImage"];   //does this need to be retained?
}

最佳答案

您声称位图数据包含“全零”,但每个像素仅查看一个字节。您假设第一个组件是红色组件,并且假设数据是每个组件一个字节;如果数据是alpha优先或浮点数,则这些假设中的一个或两个都将是错误的。

使用分配的缓冲区以任意格式创建位图上下文,然后将图像渲染到该上下文中。然后,您的缓冲区将包含您期望的格式的图像。

您可能还希望从基于结构的访问切换为基于字节的访问,即pixels[(row*bytesPerRow)+col],将col递增每个像素的组件数。当您使用结构访问组件时,字节序很容易成为头痛。

关于objective-c - 分析由NSAffineTransform和CILineOverlay过滤器产生的位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3029296/

相关文章:

java - 如何检查是否支持 Quartz Extreme?

ios - 设置单元格圆角和边框宽度使表格 View 滚动速度极慢

objective-c - iOS 5.1 在后台停止应用程序

objective-c - 写入文档的封闭文件夹

cocoa - 在圆形 NSView 的顶部绘制弯曲的高光色调,类似于 Quartz Composer UI 中看到的情况

ios - CATransition 提前推送转换替换内容

objective-c - 为最前面的应用程序生成键盘事件

ios - 将所有屏幕方向锁定为纵向,除了 1

ios - 使用可变参数调用 Objective-C 初始化器

iphone - NSDate 内存泄漏问题