Преобразование координат CIRectangleFeature в координаты просмотра

Я использую класс CIDetector в IOS, чтобы найти CIRectangleFeatures в моем UIImage. После этого я стремлюсь показать угловые точки, нарисованные в слое, который я затем, в свою очередь, добавляю в свой UIImageView. К сожалению, координаты, заданные с помощью CIRectangleFeature, находятся в пространстве изображения. И хотя я пытаюсь преобразовать их с помощью функции CGContextConvertToUserSpace, нарисованный прямоугольник сильно отличается от фактического прямоугольника на изображении.

Вот мой код, когда изображение берется, вызывается workWithTheImage:

func analyzeImage(image: UIImage) -> [RectanglePoint]
    {
        guard let ciImage = CIImage(image: image)
            else { return [] }

        let context = CIContext(options: nil)

        let detector = CIDetector(ofType: CIDetectorTypeRectangle, context: context, options: nil)

        let features = detector.featuresInImage(ciImage)

        UIGraphicsBeginImageContext(ciImage.extent.size)
        let currentContext = UIGraphicsGetCurrentContext()

        var points: [RectanglePoint] = []

        for feature in features as! [CIRectangleFeature]
        {
            let topLeft = CGContextConvertPointToUserSpace(currentContext, feature.topLeft)
            let topRight = CGContextConvertPointToUserSpace(currentContext, feature.topRight)
            let bottomRight = CGContextConvertPointToUserSpace(currentContext, feature.bottomRight)
            let bottomLeft = CGContextConvertPointToUserSpace(currentContext, feature.bottomLeft)

            let point = RectanglePoint(bottomLeft: bottomLeft, topLeft: topLeft, bottomRight: bottomRight, topRight: topRight)
            points.append(point)
        }

        UIGraphicsEndImageContext()
        return points
    }



    func workWithImage(image: UIImage)
    {
        let imageView = UIImageView(frame: view.frame)
        imageView.image = image

        let path = UIBezierPath()
        let shapeLayer = CAShapeLayer()
        shapeLayer.frame = imageView.bounds

        for i in analyzeImage(image)
        {
            path.moveToPoint(i.topLeft)
            path.addLineToPoint(i.topRight)
            path.addLineToPoint(i.bottomRight)
            path.addLineToPoint(i.bottomLeft)
            path.addLineToPoint(i.topLeft)
        }

        shapeLayer.path = path.CGPath
        shapeLayer.fillColor = UIColor.clearColor().CGColor
        shapeLayer.strokeColor = UIColor.redColor().CGColor

        imageView.layer.addSublayer(shapeLayer)
    }

person rodalfus    schedule 18.10.2015    source источник
comment
Вы также можете опубликовать образец изображения? CIDetector не очень точен.   -  person R Menke    schedule 18.10.2015


Ответы (1)


Если ваш путь отличается только по оси Y:

Я думаю, что они еще не полностью перенесли CIDetector на UIKit. Координаты объекта находятся в системе координат Cocoa. Простое выполнение container.height - point.y преобразует его.

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

Код :

func analyzeImage(image: UIImage) -> [Quadrilateral]
{
    guard let ciImage = CIImage(image: image)
        else { return [] }

    let flip = true // set to false to prevent flipping the coordinates

    let context = CIContext(options: nil)

    let detector = CIDetector(ofType: CIDetectorTypeRectangle, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])

    let features = detector.featuresInImage(ciImage)

    UIGraphicsBeginImageContext(ciImage.extent.size)
    let currentContext = UIGraphicsGetCurrentContext()

    var frames: [Quadrilateral] = []

    for feature in features as! [CIRectangleFeature]
    {
        var topLeft = CGContextConvertPointToUserSpace(currentContext, feature.topLeft)
        var topRight = CGContextConvertPointToUserSpace(currentContext, feature.topRight)
        var bottomRight = CGContextConvertPointToUserSpace(currentContext, feature.bottomRight)
        var bottomLeft = CGContextConvertPointToUserSpace(currentContext, feature.bottomLeft)

        if flip {
            topLeft = CGPoint(x: topLeft.x, y: image.size.height - topLeft.y)
            topRight = CGPoint(x: topRight.x, y: image.size.height - topRight.y)
            bottomLeft = CGPoint(x: bottomLeft.x, y: image.size.height - bottomLeft.y)
            bottomRight = CGPoint(x: bottomRight.x, y: image.size.height - bottomRight.y)
        }

        let frame = Quadrilateral(topLeft: topLeft, topRight: topRight, bottomLeft: bottomLeft, bottomRight: bottomRight)

        frames.append(frame)
    }

    UIGraphicsEndImageContext()
    return frames
}

Четырехсторонняя структура:

struct Quadrilateral {
    var topLeft : CGPoint = CGPointZero
    var topRight : CGPoint = CGPointZero
    var bottomLeft : CGPoint = CGPointZero
    var bottomRight : CGPoint = CGPointZero

    var path : UIBezierPath {
        get {
            let tempPath = UIBezierPath()
            tempPath.moveToPoint(topLeft)
            tempPath.addLineToPoint(topRight)
            tempPath.addLineToPoint(bottomRight)
            tempPath.addLineToPoint(bottomLeft)
            tempPath.addLineToPoint(topLeft)
            return tempPath
        }
    }

    init(topLeft topLeft_I: CGPoint, topRight topRight_I: CGPoint, bottomLeft bottomLeft_I: CGPoint, bottomRight bottomRight_I: CGPoint) {
        topLeft = topLeft_I
        topRight = topRight_I
        bottomLeft = bottomLeft_I
        bottomRight = bottomRight_I
    }

    var frame : CGRect {
        get {
            let highestPoint = max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y)
            let lowestPoint = min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y)
            let farthestPoint = max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x)
            let closestPoint = min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x)

            // you might want to set origin to (0,0)
            let origin = CGPoint(x: closestPoint, y: lowestPoint)
            let size = CGSize(width: farthestPoint, height: highestPoint)

            return CGRect(origin: origin, size: size)
        }
    }

    var size : CGSize {
        get {
            return frame.size
        }
    }

    var origin : CGPoint {
        get {
            return frame.origin
        }
    }
}
person R Menke    schedule 18.10.2015
comment
@R Menke, можете ли вы дать решение в задаче c, пожалуйста - person Manikandan D; 07.09.2017