A work-in-progress trying to push image generation models to the limits for virtual staging for empty homes. Turn a folder of raw real-estate listing photos of an empty house into fully furnished, photorealistic staged images: automatically, and consistently across every angle of each room.
Image generation models have no true sense of spatial awareness across multiple images. Virtual staging has to be consistent, if I have 3 photos of one room and I want coherency in the staged images, I need the exact same bed in the exact same spot across both images. This is the challenge I am trying to solve, how do you drop in 30 photos of the same house and make the generated furniture coherent?
With enough prompting, you can get a frontier image generation model to create identical furniture in the same place, across multiple photos of the same room. If I have 3 image generation models running seperately, and I pass them each one image of the same room, and I give enough instruction to each model relative to the other models, I should get coherent output.
I have gotten impressive results in some instances. Take a bathroom, for example. There are distinct parts of the room that the models can't misinterpret: the vanity, the shower, the mirror. These give you referential anchor points to instruct the model. "Place a white hand soap dispenser to the left of the sink" does not depend on the perspective, in 99/100 cases, the model places the white dispenser to the left of the sink. With enough description of the items to place (style, color, distance from wall, orientation) you can get extremely good output.
-
Depth Maps: These have helped to an impressive degree. Models like Nano Banana Pro (Gemini-3.1-image-preview) work exceptionally better in spatial analysis of a room when also given a depthMap.jpeg of the room they are looking at. They understand doors, angles, relationship to the camera, and orientation better. This also helps to ensure the model does not change any of the existing room, but merely adds things to it.
-
Sorting: This has worked really well. Taking all 30+ images of a house, and passing them all to one model to sort to 'bedroom_1' and 'bedroom_2' and so on, especially when given how many bedrooms, bathrooms, and living spaces there are so the sorting model knows "I have 4 bedrooms to sort images into".
-
Prompt Generation: What has worked the best for me is taking each room, and in parallel (mainly for speed) send each room to Gemini Flash to create the prompts. Flash sees all the images of a given room, is given a description of the style of staging to do, and then generates a PER image prompt to then go to the image generation model. This is where we get the coherency, but altered per room. Then we split those prompts, pair them with the images, and send to Gemini on a per image basis to create the staged images.
-
Out of frame objects: If in one image, a bed would be completely visible and in frame, no problem. As soon as the bed would be clipping into frame, getting Gemini-3.1-Image-Preview to generate and interpret that correctly seems like a roll of the dice.
-
Large rooms/Open Concept: Any wide open kitchen or living areas that span multiple rooms and have 6+ images seem to fall apart. I need to get that sorted. Trying in this concept to get coherency across that many images, is seemingly impossible.
-
Non-descript rooms: Any bedrooms with closets or doors where you cannot make out which is which has confused some of the sorting models. This is where I was trying to get into deterministic matching. Based of images angles, door spacing, any mathematical data we can withdraw, match images to each other. Some times on certain rooms the sorting model was mis-labeling which image was from which angle in the room. A deterministic 3D reconstruction tool would fix this.
-
Too much decor: The less items I try to add, the better. But this isn't what realtors want, they want life added to the rooms. Not a bedroom and a desk. There needs to be a way to have tons of items, decor, and furniture without degredation of consistency.
Gemini??? What is wrong with me? I know, I know. I picked Gemini because 3.1 Preview seems to have the best results, both in quality but also the ability to interpret the prompt and take depth maps as input. It's fast, and relatively cheap. I know there are some cross-image spatial awareness models that exist, but the image quality is lacking.
The project has two parts:
staging/— a generative staging pipeline that sorts photos by room, locks each shot's geometry with depth + line conditioning, and stages every room consistently using Google Gemini.deterministic_matching/— a no-LLM computer-vision module that recovers a room's spatial structure (which walls are which, how photos overlap) so multi-angle staging stays coherent.
A single automated run (python -m staging.run) takes a folder of listing photos and produces staged rooms in four steps:
| Step | What happens | Model / tool |
|---|---|---|
| 1. Sort | One batched call clusters every photo into room groups (kitchen, master bedroom, …) | Gemini 3 Flash |
| 2. Prep | Generates a depth map + an MLSD wireframe per photo to pin geometry | controlnet_aux (MiDaS + MLSD) |
| 3. Analyze | Per room, produces a shared furniture spec + a per-image staging prompt | Gemini 3.1 Pro |
| 4. Stage | Stages every image in parallel, conditioned on its depth + wireframe | Gemini 3.1 Flash Image |
Rooms run concurrently on a thread pool, and the per-room batching is what keeps furniture consistent across all angles of the same room — the design goal that drove the whole pipeline.
The pipeline is split into focused modules:
staging/
├── run.py # orchestration + CLI entry (python -m staging.run)
├── config.py # models, sizes, room taxonomy, paths
├── prompts.py # analysis + staging prompt templates
├── client.py # GenAI client, env loading, retry/backoff
├── images.py # input/source-image discovery
├── sort.py # Step 1 — classify + cluster into rooms
├── generate_depth_map.py # MiDaS depth maps
├── generate_wireframe.py # MLSD wireframes
├── prep.py # Step 2 — depth + wireframe per room
├── analyze.py # Step 3 — per-image staging prompts
├── stage.py # Step 4 — render one image
└── pipeline.py # per-room prep → analyze → stage
A deterministic CV prepass (no LLMs): given 2–5 photos of one room, it extracts ORB features, estimates homographies / fundamental matrices with RANSAC, analyzes wall lines, and emits structured JSON describing wall-plane assignments and pairwise overlap. It ships with its own README and a pytest suite. See it for details.
Stack: Python · Google Gemini (google-genai) · controlnet_aux (MiDaS, MLSD) · OpenCV · NumPy / SciPy · optional LightGlue
pip install -r requirements.txt
cp .env.example .env # then add your GOOGLE_API_KEY# Drop listing photos into staging/input/, then run the full pipeline:
python -m staging.runRun the deterministic room analysis on its own:
cd deterministic_matching
pip install -r requirements.txt
python -m deterministic_matching.main -i ./inputSample input/output images are intentionally omitted — the originals were real property photos. Bring your own photos in
staging/input/.