如何在iOS中将2D矩阵中的不规则连接区域转换为矩形?

w80xi6nr  于 11个月前  发布在  iOS
关注(0)|答案(1)|浏览(82)

我有一个513*513的矩阵,它表示人分割的结果。
现在我想把不规则的连接区域转换成矩形。
它看起来像下面的图像:


的数据
我的代码是:

func findConnectedRegion(matrix: [[Int]]) -> [[(Int, Int)]] {
        var result: [[(Int, Int)]] = []
        //    var visited: Set<(Int, Int)> = []
        var visited: Set<String> = []
        let numRows = matrix.count
        let numCols = matrix[0].count
        
        for i in 0..< numRows {
            for j in 0..< numCols {
                let position = (i, j)
                self.str = String(i)+"-"+String(j)
                if matrix[i][j] == 15 && !visited.contains(self.str) {
                    var region: [(Int, Int)] = []
                    dfs(matrix: matrix, rows: numRows,cols: numCols,position: position, visited: &visited, region: &region)
                    result.append(region)
                }
            }
        }
        
        return result
    }
    
    func dfs(matrix: [[Int]],rows:Int,cols:Int,position: (Int, Int), visited: inout Set<String>, region: inout [(Int, Int)]) {
//        let numRows = matrix.count
//        let numCols = matrix[0].count
        
        let numRows = rows
        let numCols = cols
        
        let (row, col) = position
        self.str = String(position.0)+"-"+String(position.1)
        
        // Check if the current position is within bounds and is part of the region
        guard row >= 0, row < numRows, col >= 0, col < numCols, matrix[row][col] == 15, !visited.contains(self.str) else {
            return
        }
        
        visited.insert(self.str)
        region.append(position)
        
        // Explore neighbors in all four directions
        dfs(matrix: matrix,rows: numRows,cols: numCols, position: (row - 1, col), visited: &visited, region: &region)  // Up
        dfs(matrix: matrix, rows: numRows,cols: numCols,position: (row + 1, col), visited: &visited, region: &region)  // Down
        dfs(matrix: matrix, rows: numRows,cols: numCols,position: (row, col - 1), visited: &visited, region: &region)  // Left
        dfs(matrix: matrix, rows: numRows,cols: numCols,position: (row, col + 1), visited: &visited, region: &region)  // Right
    }

字符串
但它总是有一个错误,如线程1:EXC_BAD_ACCESS(code=2,address=0xxxxxxx

它看起来像一个堆栈溢出错误,但我不确定。我怎么才能解决这个问题?
arrayFile在这里:https://gofile.io/d/Ijmok8
将其转换为数组:

if let data = try? Data(contentsOf: filePath, options: .mappedIfSafe), 
let array = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) {
                            
                        }


我想做的是把不规则的15个相连的区域变成矩形。
然后通过以下方式绘制图像:

func drawImage(array: [[Int]], completion: @escaping (UIImage?) -> Void) {
        let m = array.count
        let n = array[0].count
        let size = CGSize(width: m, height: n)
        

        DispatchQueue.global(qos: .userInitiated).async {
            let renderer = UIGraphicsImageRenderer(size: size)
            

            let image = renderer.image { (context) in

                let cgContext = context.cgContext
                
                let black = UIColor.black
                let white = UIColor.white

                for j in 0..<n {
                    for i in 0..<m {
                        let value = array[i][j]
                        let rect = CGRect(x: i, y: j, width: 1, height: 1)
                        if value == 15 {
                            
                            cgContext.setFillColor(black.cgColor)
                            cgContext.fill(rect)
                            
                        } else {
                            cgContext.setFillColor(white.cgColor)
                            cgContext.fill(rect)
                        }
                        
                    }
                }
            }
            
            DispatchQueue.main.async {
                completion(image)
            }
            
            
        }


结果与右上角的图像不一样,如果它显示矩形也没关系。
谢谢

tyg4sfes

tyg4sfes1#

很可能,是的,你遇到了一个内存错误,由于String的巨大Set.
我对你的代码做了一些修改,使用了Set<CGPoint>,不再出现崩溃(还添加了一点代码来在形状周围绘制矩形):

// we want to use a Set of CGPoint
//  so we need to make it Hashable
extension CGPoint : Hashable {
    public func hash(into hasher: inout Hasher) {
        hasher.combine(x)
        hasher.combine(y)
    }
}

class MatrixVC: UIViewController {
    
    let imgView = UIImageView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemYellow
        
        imgView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imgView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            imgView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            imgView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            imgView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
        ])
        
        guard let filePath = Bundle.main.url(forResource: "arrayFile", withExtension: "json") else { fatalError() }
        
        if let data = try? Data(contentsOf: filePath, options: .mappedIfSafe),
           let array = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves),
           let a = array as? [[Int]]
        {
            let t = findConnectedRegion(matrix: a)
            
            var rects: [CGRect] = []
            
            for i in 0..<t.count {
                let mnx = t[i].min(by: { $0.0 < $1.0 }) ?? (0, 0)
                let mxx = t[i].max(by: { $0.0 < $1.0 }) ?? (0, 0)
                let mny = t[i].min(by: { $0.1 < $1.1 }) ?? (0, 0)
                let mxy = t[i].max(by: { $0.1 < $1.1 }) ?? (0, 0)
                
                let r: CGRect = .init(x: mnx.0, y: mny.1, width: mxx.0 - mnx.0, height: mxy.1 - mny.1)
                rects.append(r)
            }
            
            drawImage(array: a, rects: rects, completion: { img in
                guard let img = img else { fatalError() }
                self.imgView.heightAnchor.constraint(equalTo: self.imgView.widthAnchor, multiplier: img.size.height / img.size.width).isActive = true
                self.imgView.image = img
            })

        }
    }
    
    func drawImage(array: [[Int]], rects: [CGRect], completion: @escaping (UIImage?) -> Void) {
        let m = array.count
        let n = array[0].count
        let size = CGSize(width: m, height: n)
        
        DispatchQueue.global(qos: .userInitiated).async {
            let renderer = UIGraphicsImageRenderer(size: size)
            
            let rectColors: [UIColor] = [
                .systemRed, .systemGreen, .systemBlue
            ]
            
            let image = renderer.image { (context) in
                let cgContext = context.cgContext
                
                let black = UIColor.black
                let white = UIColor.white
                
                for j in 0..<n {
                    for i in 0..<m {
                        let value = array[i][j]
                        let rect = CGRect(x: i, y: j, width: 1, height: 1)
                        if value == 15 {
                            
                            cgContext.setFillColor(black.cgColor)
                            cgContext.fill(rect)
                            
                        } else {
                            cgContext.setFillColor(white.cgColor)
                            cgContext.fill(rect)
                        }
                        
                    }
                }
                
                for i in 0..<rects.count {
                    cgContext.setStrokeColor(rectColors[i % rectColors.count].cgColor)
                    cgContext.stroke(rects[i])
                }
                
            }
            
            DispatchQueue.main.async {
                completion(image)
            }
            
            
        }
    }
    
    var curPoint: CGPoint = .zero
    
    func findConnectedRegion(matrix: [[Int]]) -> [[(Int, Int)]] {
        var result: [[(Int, Int)]] = []
        var visitedPoints: Set<CGPoint> = []
        let numRows = matrix.count
        let numCols = matrix[0].count
        
        for i in 0..<numRows {
            for j in 0..<numCols {
                let position = (i, j)
                self.curPoint = .init(x: i, y: j)
                if matrix[i][j] == 15 && !visitedPoints.contains(self.curPoint) {
                    var region: [(Int, Int)] = []
                    dfsP(matrix: matrix, rows: numRows,cols: numCols,position: position, visited: &visitedPoints, region: &region)
                    result.append(region)
                }
            }
        }
        return result
    }
    
    func dfsP(matrix: [[Int]],rows:Int,cols:Int,position: (Int, Int), visited: inout Set<CGPoint>, region: inout [(Int, Int)]) {
        let numRows = rows
        let numCols = cols
        
        let (row, col) = position
        self.curPoint = .init(x: position.0, y: position.1)
        
        // Check if the current position is within bounds and is part of the region
        guard row >= 0, row < numRows, col >= 0, col < numCols, matrix[row][col] == 15, !visited.contains(self.curPoint) else {
            return
        }
        
        visited.insert(self.curPoint)
        region.append(position)
        
        // Explore neighbors in all four directions
        dfsP(matrix: matrix,rows: numRows,cols: numCols, position: (row - 1, col), visited: &visited, region: &region)  // Up
        dfsP(matrix: matrix, rows: numRows,cols: numCols,position: (row + 1, col), visited: &visited, region: &region)  // Down
        dfsP(matrix: matrix, rows: numRows,cols: numCols,position: (row, col - 1), visited: &visited, region: &region)  // Left
        dfsP(matrix: matrix, rows: numRows,cols: numCols,position: (row, col + 1), visited: &visited, region: &region)  // Right
    }
    
}

字符串
测试结果:
x1c 0d1x的数据
我使用了你的json文件.不知道如果你有一个更大的数组,这是否会再次遇到问题-我将把它留给你测试。
顺便说一下,您可能希望使用Vision框架研究VNDetectContoursRequest

相关问题