我正在尝试使用CIFilters链操作图像,然后检查结果图像(位图)的每个字节。从长远来看,我不需要显示结果图像(位图) --我只需要在内存中“分析”它。但近期我会将其显示在屏幕上,以帮助调试。
我有一些“位图检查”代码,在检查我用作输入(从JPG文件加载到NSImage中)的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中(或“应该是”)中的位图。并且该代码仅适用于由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?
}发布于 2010-06-15 10:40:22
您声称位图数据包含“全零”,但是您看到的是每个像素只有一个字节。假设第一个组件是红色组件,并且假设数据是每个组件一个字节;如果数据是alpha优先或浮点数,那么这两个假设中的一个或两个都将是错误的。
使用分配的缓冲区以任何格式创建位图上下文,并将图像渲染到该上下文中。然后,您的缓冲区将包含您所期望的格式的图像。
您可能还希望从基于结构的访问切换到基于字节的访问-即pixels[(row*bytesPerRow)+col],按每个像素的组件数量递增col。在使用结构访问组件时,字节序很容易成为一个令人头疼的问题。
发布于 2010-06-14 13:29:52
(row = 0;row < heightInPixels;row++) for (column = 0;column < widthInPixels;column++) { if (row == 1340) {//只检查这一行,我知道预期的NSLog(@"Row 1340 Column%d pixel of pixel is %d",column,thisPixel->column++);}}
除了语法错误之外,此代码无法工作,因为您从未将此代码赋值给thisPixel。您是在毫无意义地遍历索引,因为您从未真正在这些索引处查找像素值并将其赋给thisPixel以检查它。
在NSLog语句之前添加这样的赋值。
此外,如果您只关心1340行,则不需要遍历各行。使用if语句检查1340是否小于高度,如果是,则只执行列循环。(另外,不要在代码中嵌入像这样的幻数文字。给这个常量起一个名字来解释数字1340的意义--也就是为什么你只关心这一行。)
https://stackoverflow.com/questions/3029296
复制相似问题