Skip to content

Commit

Permalink
Merge pull request #59 from valeriyvan/refactor/differenceFull
Browse files Browse the repository at this point in the history
Move differenceFull into Bitmap extension
  • Loading branch information
valeriyvan authored Oct 8, 2023
2 parents d604a66 + 6c09e5e commit 84211fd
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 37 deletions.
27 changes: 27 additions & 0 deletions Sources/geometrize/Bitmap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,30 @@ extension Bitmap {
}

}

extension Bitmap {

/// Calculates the root-mean-square error between two bitmaps.
func differenceFull(with second: Bitmap) -> Double {
assert(width == second.width)
assert(height == second.height)

var total: Int64 = 0

for y in 0..<height {
for x in 0..<width {
let f: Rgba = self[x, y]
let s: Rgba = second[x, y]

let dr: Int32 = Int32(f.r) - Int32(s.r)
let dg: Int32 = Int32(f.g) - Int32(s.g)
let db: Int32 = Int32(f.b) - Int32(s.b)
let da: Int32 = Int32(f.a) - Int32(s.a)
total += Int64(dr * dr + dg * dg + db * db + da * da)
}
}

return sqrt(Double(total) / (Double(width) * Double(height) * 4.0)) / 255.0
}

}
29 changes: 0 additions & 29 deletions Sources/geometrize/Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,35 +112,6 @@ func computeColor(
return Rgba(r: r, g: g, b: b, a: alpha)
}

/// Calculates the root-mean-square error between two bitmaps.
/// - Parameters:
/// - first: The first bitmap.
/// - second: The second bitmap.
/// - Returns: The difference/error measure between the two bitmaps.
func differenceFull(first: Bitmap, second: Bitmap) -> Double {
assert(first.width == second.width)
assert(first.height == second.height)

let width = first.width
let height = first.height
var total: Int64 = 0

for y in 0..<height {
for x in 0..<width {
let f: Rgba = first[x, y]
let s: Rgba = second[x, y]

let dr: Int32 = Int32(f.r) - Int32(s.r)
let dg: Int32 = Int32(f.g) - Int32(s.g)
let db: Int32 = Int32(f.b) - Int32(s.b)
let da: Int32 = Int32(f.a) - Int32(s.a)
total += Int64(dr * dr + dg * dg + db * db + da * da)
}
}

return sqrt(Double(total) / (Double(width) * Double(height) * 4.0)) / 255.0
}

/// Calculates the root-mean-square error between the parts of the two bitmaps within the scanline mask.
/// This is for optimization purposes, it lets us calculate new error values only for parts of the image
/// we know have changed.
Expand Down
6 changes: 3 additions & 3 deletions Sources/geometrize/GeometrizeModelBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class GeometrizeModelBase {
init(targetBitmap: Bitmap) {
self.targetBitmap = targetBitmap
currentBitmap = Bitmap(width: targetBitmap.width, height: targetBitmap.height, color: targetBitmap.averageColor())
lastScore = differenceFull(first: targetBitmap, second: currentBitmap)
lastScore = targetBitmap.differenceFull(with: currentBitmap)
}

/// Creates a model that will optimize for the given target bitmap, starting from the given initial bitmap.
Expand All @@ -19,7 +19,7 @@ class GeometrizeModelBase {
init(target: Bitmap, initial: Bitmap) {
targetBitmap = target
currentBitmap = initial
lastScore = differenceFull(first: target, second: currentBitmap)
lastScore = target.differenceFull(with: currentBitmap)
assert(target.width == currentBitmap.width)
assert(target.height == currentBitmap.height)
}
Expand All @@ -28,7 +28,7 @@ class GeometrizeModelBase {
/// - Parameter backgroundColor: The starting background color to use.
func reset(backgroundColor: Rgba) {
currentBitmap.fill(color: backgroundColor)
lastScore = differenceFull(first: targetBitmap, second: currentBitmap)
lastScore = targetBitmap.differenceFull(with: currentBitmap)
}

var width: Int { targetBitmap.width }
Expand Down
10 changes: 5 additions & 5 deletions Tests/geometrizeTests/CoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,37 @@ final class CoreTests: XCTestCase {
let blackBitmap = Bitmap(width: 10, height: 10, color: .black)

// Difference with itself is 0
XCTAssertEqual(differenceFull(first: blackBitmap, second: blackBitmap), 0)
XCTAssertEqual(blackBitmap.differenceFull(with: blackBitmap), 0)

var blackBitmapOnePixelChanged = blackBitmap
blackBitmapOnePixelChanged[0, 0] = .white
var blackBitmapTwoPixelsChanged = blackBitmapOnePixelChanged
blackBitmapTwoPixelsChanged[0, 1] = .white

// Changing two pixels means there's more difference than changing one.
XCTAssertTrue(differenceFull(first: blackBitmap, second: blackBitmapTwoPixelsChanged) > differenceFull(first: blackBitmap, second: blackBitmapOnePixelChanged))
XCTAssertTrue(blackBitmap.differenceFull(with: blackBitmapTwoPixelsChanged) > blackBitmap.differenceFull(with: blackBitmapOnePixelChanged))

// Now the same for white image
let whiteBitmap = Bitmap(width: 10, height: 10, color: .white)

// Difference with itself is 0
XCTAssertEqual(differenceFull(first: whiteBitmap, second: whiteBitmap), 0)
XCTAssertEqual(whiteBitmap.differenceFull(with: whiteBitmap), 0)

var whiteBitmapOnePixelChanged = whiteBitmap
whiteBitmapOnePixelChanged[0, 0] = .black
var whiteBitmapTwoPixelsChanged = whiteBitmapOnePixelChanged
whiteBitmapTwoPixelsChanged[0, 1] = .black

// Changing two pixels means there's more difference than changing one.
XCTAssertTrue(differenceFull(first: whiteBitmap, second: whiteBitmapTwoPixelsChanged) > differenceFull(first: whiteBitmap, second: whiteBitmapOnePixelChanged))
XCTAssertTrue(whiteBitmap.differenceFull(with: whiteBitmapTwoPixelsChanged) > whiteBitmap.differenceFull(with: whiteBitmapOnePixelChanged))
}

func testDifferenceFullComparingResultWithCPlusPlus() throws {
let firstUrl = Bundle.module.url(forResource: "differenceFull bitmap first", withExtension: "txt")!
let bitmapFirst = Bitmap(stringLiteral: try String(contentsOf: firstUrl))
let secondUrl = Bundle.module.url(forResource: "differenceFull bitmap second", withExtension: "txt")!
let bitmapSecond = Bitmap(stringLiteral: try String(contentsOf: secondUrl))
XCTAssertEqual(differenceFull(first: bitmapFirst, second: bitmapSecond), 0.170819, accuracy: 0.000001)
XCTAssertEqual(bitmapFirst.differenceFull(with: bitmapSecond), 0.170819, accuracy: 0.000001)
}

func testDifferencePartialComparingResultWithCPlusPlus() throws {
Expand Down

0 comments on commit 84211fd

Please sign in to comment.