import Foundation let data = try! Data(contentsOf: URL(fileURLWithPath: "shot.bmp")) // BMP header parsing let pixOff = data.withUnsafeBytes { $0.load(fromByteOffset: 10, as: UInt32.self) } let w = Int(data.withUnsafeBytes { $0.load(fromByteOffset: 18, as: Int32.self) }) let hRaw = Int(data.withUnsafeBytes { $0.load(fromByteOffset: 22, as: Int32.self) }); let h = abs(hRaw) let bpp = data.withUnsafeBytes { $0.load(fromByteOffset: 28, as: UInt16.self) } let B = Int(bpp)/8; let rowBytes = (B * w + 3) & ~3 print("bmp \(w)x\(h) bpp=\(bpp) pixOff=\(pixOff)") var minX = w, minY = h, maxX = 0, maxY = 0, count = 0 var rows: [Int] = Array(repeating: 0, count: h) for y in 0.. 0 ? (h - 1 - y) : y) * rowBytes for x in 0.. 120 && bi > ri + 30 && bi > gi + 15 && ri < 160 { count += 1; rows[y] += 1 if x < minX { minX = x }; if x > maxX { maxX = x } if y < minY { minY = y }; if y > maxY { maxY = y } } } } print("bluePixels=\(count) bbox=(\(minX),\(minY))-(\(maxX),\(maxY))") // row profile to separate blobs var bands: [(Int,Int,Int)] = [] var start = -1 for y in 0.. 20 && start < 0 { start = y } if (rows[y] <= 20 || y == h-1) && start >= 0 { bands.append((start, y, (start...y).map{rows[$0]}.max()!)); start = -1 } } for bd in bands { print("band y=\(bd.0)-\(bd.1) maxRowPx=\(bd.2)") }