Ошибка при доступе к необработанным пиксельным данным измененного изображения - PullRequest
1 голос
/ 15 июля 2011

У меня есть некоторые проблемы с доступом к изображениям с камеры (или даже к изображениям из фотальбома).

После изменения размера UIImage (я протестировал несколько разных методов изменения размера, все они приводят к одной и той же ошибке) Я хочучтобы получить доступ к каждому отдельному пикселю для передачи сложному алгоритму.

Проблема заключается в том, что часто существует значение bytesPerRow, которое не соответствует размеру изображения (например, ширина * 4) при доступе к необработанным данным пикселя с помощью CGImageGetDataProvider ->, что приводит к EXC_BAD_ACCESSошибка.

Возможно, у нас есть ошибка iOS…

Тем не менее, вот код:

// UIImage  capturedImage from Camera

CGImageRef capturedImageRef = capturedImage.CGImage;

// getting bits per component from capturedImage
size_t bitsPerComponentOfCapturedImage = CGImageGetBitsPerComponent(capturedImageRef);
CGImageAlphaInfo alphaInfoOfCapturedImage = CGImageGetAlphaInfo(capturedImageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

// calculate new size from interface data. 
// with respect to aspect ratio

// ...

// newWidth = XYZ;
// newHeight = XYZ;

CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, bitsPerComponentOfCapturedImage,0 , colorSpace, alphaInfoOfCapturedImage);

// I also tried to make use getBytesPerRow for CGBitmapContextCreate resulting in the same error

// if image was rotated
if(capturedImage.imageOrientation == UIImageOrientationRight) {
  CGContextRotateCTM(context, -M_PI_2);
  CGContextTranslateCTM(context, -newHeight, 0.0f);
}

// draw on new context with new size
CGContextDrawImage(context, CGRectMake(0, 0, newWidth, newHeight), capturedImage.CGImage);

CGImageRef scaledImage=CGBitmapContextCreateImage(context);

// release
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
theImage = [UIImage imageWithCGImage: scaledImage];

CGImageRelease(scaledImage);

После этого я хочу получить доступ к масштабированному изображению с помощью

CGImageRef imageRef = theImage.CGImage;
NSData *data        = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(imageRef));

unsigned char *pixels        = (unsigned char *)[data bytes];

// create a new image from the modified pixel data
size_t width                    = CGImageGetWidth(imageRef);
size_t height                   = CGImageGetHeight(imageRef);
size_t bitsPerComponent         = CGImageGetBitsPerComponent(imageRef);
size_t bitsPerPixel             = CGImageGetBitsPerPixel(imageRef);
size_t bytesPerRow              = CGImageGetBytesPerRow(imageRef);

CGDataProviderRef provider      = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL);

NSLog(@"bytesPerRow: %f ", (float)bytesPerRow);
NSLog(@"Image width: %f ", (float)width);
NSLog(@"Image height: %f ", (float)height);

// manipulate the individual pixels
for(int i = 0; i < [data length]; i += 4) {

  // accessing (float) pixels[i];
  // accessing (float) pixels[i+1];
  // accessing (float) pixels[i+2];

}

Так, например, когда я получаю доступ к изображению с 511x768 пикселей и масштабирую его до 290x436, я получаю следующий вывод:

Ширина изображения: 290.000000

Высота изображения: 436.000000

битPerComponent: 8.000000

битPerPixel: 32.000000

bytesPerRow: 1184.000000

, и вы можете четко видеть, что bytesPerRow (хотя и выбирается автоматически какао) не соответствует изображению width.

Я хотел бы видеть любую помощь


Использование iOS SDK 4.3 на Xcode 4

1 Ответ

1 голос
/ 15 июля 2011

Вы игнорируете возможное заполнение строк, следовательно, получаете неверные результаты.Добавьте следующий код и замените ваш цикл:

size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
//calculate the padding just to see what is happening
size_t padding = bytesPerRow - (width * bytesPerPixel);
size_t offset = 0;
// manipulate the individual pixels
while (offset < [data length])
{
  for (size_t x=0; x < width; x += bytesPerPixel)
  {
    // accessing (float) pixels[offset+x];
    // accessing (float) pixels[offset+x+1];
    // accessing (float) pixels[offset+x+2];
  }
  offset += bytesPerRow;
};

Приложение: Основным аргументом для заполнения строк является оптимизация доступа к памяти для отдельных строк до 32-битных границ.Это действительно очень часто и делается для оптимизации.

...