Measuring architecture drift in AI-edited room photos with OpenCV A developer has published an OpenCV-based method for scoring "architecture drift" in AI-staged real-estate photos, measuring whether walls, windows and door frames stay put when a tool virtually furnishes an empty room. The approach fits a RANSAC similarity transform on SIFT features from the upper wall and ceiling region to cancel zoom, shift and rotation, then compares blurred Canny edge maps with SSIM and checks Hough-line recall for structural elements, deliberately excluding the floor where furniture sits. The author notes the score answers only whether the architecture is still where it was, keeping realism ratings separate, and publishes scores for ten fixed rooms with documented thresholds on stagingbench.org. When an AI tool stages an empty room, the furniture is the easy part to judge. The hard part is whether the room itself is still the same room. If a window shrank or a wall moved by a hand's width, a buyer will notice at the showing, even if the sofa looks great. This post describes a simple way to measure that with OpenCV. It is the idea behind the "architecture drift" score in our benchmark, shown here as a sketch rather than the full production script. Many tools return the same room, slightly zoomed or shifted. That is a framing problem, not moved walls, so we estimate the geometric transform first. We match SIFT features on the top part of the frame only walls and ceiling, where furniture rarely sits and fit a similarity transform scale, rotation, shift with RANSAC. Furniture and decor become outliers and are ignored. python import cv2 import numpy as np def estimate transform orig gray, out gray, wall fraction=0.65 : h = int orig gray.shape 0 wall fraction sift = cv2.SIFT create k1, d1 = sift.detectAndCompute orig gray :h , None k2, d2 = sift.detectAndCompute out gray :h , None matches = cv2.BFMatcher .knnMatch d2, d1, k=2 good = m for m, n in matches if m.distance < 0.75 n.distance src = np.float32 k2 m.queryIdx .pt for m in good dst = np.float32 k1 m.trainIdx .pt for m in good matrix, inliers = cv2.estimateAffinePartial2D src, dst, method=cv2.RANSAC return matrix, int inliers.sum if inliers is not None else 0 The matrix tells you how much the output was zoomed, shifted and rotated. Those numbers are worth reporting on their own. After aligning the output to the original, compare only the structural parts of the image. Compute edge maps and compare them on the overlapping region, ignoring the floor where furniture stands. python from skimage.metrics import structural similarity as ssim def edge map gray : return cv2.Canny cv2.GaussianBlur gray, 5, 5 , 0 , 60, 160 def drift ssim orig gray, aligned gray : a = cv2.GaussianBlur edge map orig gray , 7, 7 , 0 b = cv2.GaussianBlur edge map aligned gray , 7, 7 , 0 return ssim a, b Blurring the edge maps first makes the score tolerant of a pixel or two of difference, so it reacts to a moved window and not to anti-aliasing. Walls, window frames and door frames are long straight lines. Detect them in the original with a Hough transform, then check what share of them is still present in the output within a few pixels. A low recall means structure was lost or moved. Edge comparison cannot tell a good redraw from a bad one, and it does not rate realism. It answers one narrow question: is the architecture still where it was? We keep realism ratings separate for that reason. Run the same tool on the same photo twice and see how much the score varies, then compare two tools. If you want to see the scores for ten fixed rooms side by side, along with the documented method and thresholds, they are on stagingbench.org https://stagingbench.org , and the checks are described on the methodology page https://stagingbench.org/methodology.html .