Быстрая обработка изображений: рассчитать текстуру UIImage как 1 двойной - PullRequest
1 голос
/ 19 сентября 2019

Я пишу приложение iOs для обработки изображений, и в настоящее время я разрабатываю метод извлечения текстуры из UIImage.Метод принимает UIImage в качестве входных данных и дает одно значение (Double) в качестве выходных данных.Чем выше текстура, тем выше будет выходное значение.Таким образом, входные изображения могут быть классифицированы от низкой текстуры до высокой текстуры.См. Фото 1, чтобы понять разницу между текстурированным и гладким изображением.

Фото 1: изображения с высокой или низкой текстурой

Мой метод основан на статистических данных.определение текстуры (см. презентацию PPT Университета Пердью для получения дополнительной информации о текстуре: http://www.cyto.purdue.edu/cdroms/micro2/content/education/wirth06.pdf?fbclid=IwAR0_7ttvNAtVqY9gWkaE_TZhivmXnZIPv1UwByTr8eFW_zAZ_Uxg6kcQ3z0).

Фото 2: определение пикселя, квадрата, входное изображение

Входные изображения будут иметь размеры точно 600px x 600 px. Чтобы определить общую текстуру изображения, я делю изображение на квадраты размером 3x3 пикселя. Для каждого пикселя в квадрате я вычисляю значение в градациях серого. После этогоминимальное и максимальное значение шкалы серого рассчитывается для каждого квадрата. Наконец, разница определяется как максимум - минимум. Эта разница рассчитывается для каждого квадрата 3x3 на изображении. Затем из всех этих значений разности складывается сумма, которая дает нам«Текстура». Чем выше эта сумма различий, тем выше текстура на изображении. См. Фото2 для получения дополнительной информации.

Сначала в Swift определены пиксель, квадрат и изображение:

struct Pixel {
    var value: UInt32
    var red: UInt8 {
        get { return UInt8(value & 0xFF) }
        set { value = UInt32(newValue) | (value & 0xFFFFFF00) }
    }
    var green: UInt8 {
        get { return UInt8((value >> 8) & 0xFF) }
        set { value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF) }
    }
    var blue: UInt8 {
        get { return UInt8((value >> 16) & 0xFF) }
        set { value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF) }
    }
    var alpha: UInt8 {
        get { return UInt8((value >> 24) & 0xFF) }
        set { value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF) }
    }
}

struct Square {
    var pixels: UnsafeMutableBufferPointer<Pixel>
    let width:Int = 3
    let height:Int = 3

    init?(zeroX: Int, zeroY: Int) {
        //pixelArray[0] = UnsafeMutableBufferPointer<Pixel>()
        //let coordinates = CGPoint(x: zeroX, y: zeroY)

        let bitsPerComponent = 8 // 2
        let bytesPerPixel = 4
        let bytesPerRow = width * bytesPerPixel
        let squareData = UnsafeMutablePointer<Pixel>.allocate(capacity: width * height)
        let colorSpace = CGColorSpaceCreateDeviceGray()
        var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Big.rawValue
        bitmapInfo |= CGImageAlphaInfo.premultipliedLast.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
        guard let imageContext = CGContext(data: squareData, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { return nil }
        //imageContext.draw(cgImage, in: CGRect(origin: .zero, size: image.size))

        pixels = UnsafeMutableBufferPointer<Pixel>(start: squareData, count: width * height)
    }
}

struct RGBA {
    var pixels: UnsafeMutableBufferPointer<Pixel>
    var width: Int
    var height: Int
    init?(image: UIImage) {
        guard let cgImage = image.cgImage else { return nil } // 1

        width = Int(image.size.width)
        height = Int(image.size.height)
        let bitsPerComponent = 8 // 2

        let bytesPerPixel = 4
        let bytesPerRow = width * bytesPerPixel
        let imageData = UnsafeMutablePointer<Pixel>.allocate(capacity: width * height)
        let colorSpace = CGColorSpaceCreateDeviceRGB() // 3

        var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Big.rawValue
        bitmapInfo |= CGImageAlphaInfo.premultipliedLast.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
        guard let imageContext = CGContext(data: imageData, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { return nil }
        imageContext.draw(cgImage, in: CGRect(origin: .zero, size: image.size))

        pixels = UnsafeMutableBufferPointer<Pixel>(start: imageData, count: width * height)
    }
}

Теперь, когда эти 3 определены, метод для вычисления значения разностиТребуется 1 одиночный квадрат:

func getSquareDifference(xValue:Int, yValue:Int) -> Double {
    let square = Square(zeroX: xValue, zeroY: yValue)
    var whiteValues = [Double]()

    for pixel in 0 ... square?.height {
        for pixel in 0 .. square?.width {
            var white:CGFloat = 0.0
            var alpha:CGFloat = 0.0
            let index = y * square!.width + x
            let pixel = square!.pixels[index]
            let pixelColor = UIColor.init(red: CGFloat(pixel.red), green: CGFloat(pixel.green), blue: CGFloat(pixel.blue), alpha: CGFloat(pixel.alpha))
            let pixelGreyScaleColor = pixelColor.getWhite(&white, alpha: &alpha)
            whiteValues[pixel] = white
        }
    }

    let min = whiteValues.min()
    let max = whiteValues.max()
    let difference = max - min

    return difference
}

Фото 3. Итерация цикла для всех 40 000 квадратов

Наконец, программе нужно сделать это getSquareDifference (xy) метод для каждого квадрата на изображении.Первый квадрат начинается с (0,0), затем он должен сместиться на квадрат с (3,0), пока не закончится первая горизонтальная линия (200 квадратов).Затем он принимает квадрат в (0,3) и делает то же самое для второй строки.И так по всем вертикальным линиям (200 квадратов).Пожалуйста, смотрите Фото 3 для получения дополнительной информации.

func determineTexture(inputImage:UIImage) -> Double {
    let rgba = RGBA(image: inputImage)
    var texture:Double = 0.0

    for y in 0..<rgba!.height {
        for x in 0..<rgba!.width {
            // For all squares, calculate the difference value and add to the Double 'Texture'
            // let difference = square.getSquareDifference(x,y)
            // texture += difference
        }
    }
    return texture
}

Как видите, этот метод еще не закончен.Есть еще некоторые проблемы с:

  • struct Square: Как определить квадрат, в котором находится верхний левый пиксель (x, y)?
  • func getSquareDifference (x, y) isеще не проверен, потому что все еще есть некоторые проблемы со структурой квадрата
  • func defineTexture (inputImage): как создать цикл for, который вычисляет «разностное значение» квадрата, добавляет это значение в «var texture»: Double ', переходит к следующему квадрату и повторяет этот процесс до тех пор, пока не будут вычислены все значения разностей 40 000 квадратов (200x200).

Было бы замечательно, если бы кто-то знал возможное решение этих проблем!Если этот метод работает, он будет полезен для всех, кому нужна классификация изображений, в его / ее приложении.

* Примечание: если вы хотите знать, как убедиться, что каждое изображение имеет размеры точно 600px x 600 px, я бырекомендуем следующий метод:

let compressedInputImage = inputImage.sd_resizedImage(with: CGSize(width: 600, height: 600), scaleMode: .aspectFill)
...