2016-04-17 2 views
2

Я получил изображение с большим изображением наПочему метод CGImageGetBytesPerRow() возвращает странное значение для некоторых изображений?

let partialCGImage = CGImageCreateWithImageInRect(CGImage, frame) 

но иногда я получил неправильное значение RGBA. Например, я вычислил средние красные значения изображения, но получилось как серое изображение. Итак, я проверил информацию, как следует.

image width: 64 
image height: 64 
image has 5120 bytes per row 
image has 8 bits per component 
image color space: <CGColorSpace 0x15d68fbd0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1) 
image is mask: false 
image bitmap info: CGBitmapInfo(rawValue: 8194) 
image has 32 bits per pixel 
image utt type: nil 
image should interpolate: true 
image rendering intent: CGColorRenderingIntent 
Bitamp Info: ------ 
Alpha info mask: Ture 
Float components: False 
Byte oder mask: Ture 
Byte order default: False 
Byte order 16 little: False 
Byte order 32 little: Ture 
Byte order 16 big: Ture 
Byte order 32 big: False 
Image Info ended--------------- 

Тогда я получил очень странные проблемы, поэтому ширина и высота оба 64 PXS, и изображение имеет 8 бит (1 байт) в расчете на компонент (4 байта на пиксель), но байт в строке 5120?
И я замечаю, что битмап-информация нормального изображения совсем иная, у него нет информации о байтовом порядке. Я искал разные слова между маленьким эндисом и большим эндиантом, но я смутился, когда они появились вместе. Мне действительно нужна помощь, так как из-за этого мой проект уже задерживается на 2 дня. Благодаря!

Кстати, я использовал следующий код, чтобы получить значение RGBA.

let pixelData=CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage)) 
let data:UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) 

var rs: [[Int]] = [] 
var gs: [[Int]] = [] 
var bs: [[Int]] = [] 

let widthMax = imageWidth 
let heightMax = imageHeight 
for indexX in 0...widthMax { 
     var tempR: [Int] = [] 
     var tempG: [Int] = [] 
     var tempB: [Int] = [] 
     for indexY in 0...heightMax { 
      let offSet = 4 * (indexX * imageWidth + indexY) 
      **let r = Int(data[pixelInfo + offSet]) 
      let g = Int(data[pixelInfo + 1 + offSet]) 
      let b = Int(data[pixelInfo + 2 + offSet])** 
      tempR.append(r) 
      tempG.append(g) 
      tempB.append(b) 
     } 
     rs.append(tempR) 
     gs.append(tempG) 
     bs.append(tempB) 
    } 

Спросите меня, есть ли у вас проблемы с моим кодом. Спасибо за помощь.

ответ

2

В дополнение к вопросу о pixelInfo, поднятый Сегментация, расчет offSet кажется, любопытно:

let offSet = 4 * (indexX * imageWidth + indexY) 

В x и y значения в обратном направлении. Кроме того, вы также не можете предположить, что байты для каждой строки всегда равны 4-кратной ширине в пикселях, потому что некоторые форматы изображений обрабатывают байты в строке. Во всяком случае, теоретически это должно быть:

let offSet = indexY * bytesPerRow + indexX * bytesPerPixel 

отметить также, что в дополнении к й/у оборотного вопроса, вы не хотите 0 ... widthMax и 0 ... heightMax (как те вернутся widthMax + 1 и heightMax + 1 точек данных). Вместо этого вы хотите использовать 0 ..< widthMax и 0 ..< heightMax.

Также, если вы имеете дело со случайными файлами изображений, здесь есть и другие более глубокие проблемы. Например, вы не можете делать предположения относительно RGBA против ARGB против CMYK, большого endian vs little endian и т. Д., Захваченных в информационном поле bitmap.

Вместо того, чтобы писать код, который может обрабатывать все эти вариации в пиксельных буферах, Apple предлагает альтернативу отображать произвольную конфигурацию и отображать ее в некоторой согласованной конфигурации контекста, а затем вы можете легко перемещаться по буфере. См. Technical Q&A #1509.

+0

Спасибо вам большое! Я попробовал метод, который вы упомянули, и это сработало! – JsW

+0

Но у него все еще есть одна проблема: я создаю изображение 2448 * 2222 jpeg и устанавливаю все RGB-цвета пикселей в (238, 42, 43) без альфа-канала в Photoshop. Но в моем приложении получается (231, 17, 33). Кроме того, я использую следующий алгоритм для вычисления среднего значения RGB. 'FUNC averageOfdata (Массив данных: [[Int]]) -> Int { вар resultInTotal: Int Count = 0 вар: Int = 0 для valueArray в данных { для значения в valueArray { счетчик + = 1 resultInTotal + = значение } } возвращение Int (resultInTotal/count) } ' – JsW

+0

Спросите меня, если у вас есть вопрос, спасибо за вашу помощь! – JsW

2

Прежде всего, вы не инициализировали pixelInfo переменную. Во-вторых, вы ничего не делаете с значением A, смещающим все 8 бит влево. Кроме того, я не думаю, что вам нужно pixelInfo и offset, эти две переменные являются одинаковыми, так держать одну из них равно, что вы написали для offset

+0

Извините, я просто разместил часть кода, и я забыл опубликовать эту часть кода. Я инициализировал 'pixelInfor' в начале функции. Я думал, что устало читать слишком много кода, поэтому я выбрал важную часть. Я опубликую все это и прокомментирую важную часть в следующий раз. Спасибо за помощь. – JsW

3

Байты за строку 5120, потому что вы использовали CGImageCreateWithImageInRect на большом изображении.From the CGImage reference manual:

Полученное изображение сохраняет ссылку на исходное изображение, что означает, что вы можете освободить исходное изображение после вызова этой функции.

Новое изображение использует то же хранилище пикселей, что и старое (большее) изображение. Вот почему новый образ сохраняет старый образ и почему у них одинаковые байты за строку.

Что касается того, почему вы не получаете красные значения, которые вы ожидаете: ответ Роба содержит некоторую полезную информацию, но если вы хотите глубже изучить, считайте, что ваша информация о растровых изображениях равна 8194 = 0x2002.

print(CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue) 

# Output: 
8194 

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

let context = CGBitmapContextCreate(nil, 1, 1, 8, 4, CGColorSpaceCreateDeviceRGB(), CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)! 
UIGraphicsPushContext(context) 
let d: CGFloat = 255 
UIColor(red: 1/d, green: 2/d, blue: 3/d, alpha: 1).setFill() 
UIRectFill(.infinite) 
UIGraphicsPopContext() 
let data = UnsafePointer<UInt8>(CGBitmapContextGetData(context)) 
for i in 0 ..< 4 { 
    print("\(i): \(data[i])") 
} 

# Output: 
0: 3 
1: 2 
2: 1 
3: 255 

Таким образом, мы можем видеть, что растровый информация о 8194 означает, что порядок байт BGRA. Ваш код предполагает, что это RGBA.

+0

Это помогает мне полностью понять, где моя ошибка. Спасибо за вашу помощь и такой подробный пример. Я действительно хочу сказать несколько слов, чтобы поблагодарить вас и Роба, но мой английский не позволяет мне этого. Если удобно – JsW

+0

Пожалуйста, дайте мне несколько советов о проблеме, о которой я упомянул в комментарии Роба, если это удобно для вас и Роба. – JsW

+0

Взгляните на [этот ответ] (http://stackoverflow.com/a/11065716/77567) и связанную статью. –