File size: 9,924 Bytes
c28dddb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
import os
from PIL import Image
from io import BytesIO
import base64

def encode_image(image_path: str, center_crop=False):
    """Resize and encode the image as base64"""
    # load the image
    image = Image.open(image_path)

    # resize the image to 224x224
    if center_crop: # (resize to 256x256 and then center crop to 224x224)
        image = image.resize((256, 256))
        width, height = image.size
        left = (width - 224) / 2
        top = (height - 224) / 2
        right = (width + 224) / 2
        bottom = (height + 224) / 2
        image = image.crop((left, top, right, bottom))
    else:
        image = image.resize((512, 512))

    # conver the image to bytes
    buffer = BytesIO()
    image.save(buffer, format="PNG")
    buffer.seek(0)
    # encode the image as base64
    encoded_image = base64.b64encode(buffer.read()).decode("utf-8")
    return encoded_image

system_prompt = """
You are an expert in the recognition, structural parsing, and physical‑feasibility validation of articulated objects from image inputs.

You will be provided with two rendered images of the same object:
1. A closed‑state image (all movable parts in their fully closed positions)
2. An open‑state image (all movable parts in their fully opened positions)

Your task is to analyze the object's articulated structure and generate a connectivity graph describing the part relationships.

You must follow this workflow:

1. Part Detection:
   - Detect candidate parts with their coarse position in the **closed-state image**, with optional assistance from the **open-state image** to resolve ambiguous or occluded parts.
   - Allowed part types: ['base', 'door', 'drawer', 'handle', 'knob', 'tray']
   - Ignore small decorative things directly attached to the base.
   - There must be exactly one "base"; "tray" is only allowed if the object is a microwave (but "tray" is not the component must be shown in microwave).

2. Step-by-Step Reasoning:
   1. Part Listing: List all detected parts and their counts (do not infer attachment yet) 
   2. Validation: Enforce structural rules:
      - Exactly one base
      - Each door or drawer may have at most two handles or knobs
      - Every handle/knob must attach to a door or drawer
      - Trays only appear in microwaves
   3. Attachment Inference: For each non-base part, infer its parent (e.g., "drawer_1 (attached to base)").
      - Use the open-state image to assist in verifying attachments if the closed-state image is ambiguous.
   4. Connectivity Graph Construction: Output a JSON tree of part relationships. The base is the root.

Example output:
```json
{
  "base": [
    { "door": [ { "handle": [] } ] },
    { "drawer": [ { "handle": [] } ] }
  ]
}
```

Final Output: You **MUST** output a single JSON tree representing the part connectivity of the object. Use the open-state image to improve the accuracy and completeness of your structural interpretation, but base your parsing primarily on the closed-state image.
Note: You **MUST** give the final output in JSON format.
"""

answer_sys = """
Great — please upload the two images of the same object:

One in the closed state (all movable parts fully closed)

One in the open state (all movable parts fully open)

Once I receive both, I’ll proceed with:

Part detection on the closed image

Structured reasoning and validation

Attachment inference

Final part connectivity graph in JSON format

Let me know when you're ready to continue!
"""

answer_1 = """
Great! Let’s go through the articulated object parsing workflow based on the provided **closed-state** and **open-state** images.

---

### **1. Part Detection**

From the **closed-state image** (first image), with verification from the **open-state image** (second image):

- **Base**: 1 base structure (entire wooden cabinet)
- **Doors**: 4 doors  
  - 2 on the upper section (left & right)  
  - 2 on the lower section (left & right)
- **Drawers**: 4 drawers  
  - 3 in a row at the middle  
  - 1 larger drawer centered below the middle row
- **Handles**: 8 handles  
  - 1 per drawer  
  - 1 per door

---

### **2. Step-by-Step Reasoning**

#### 2.1 **Part Listing**

- `base`: 1  
- `door`: 4  
- `drawer`: 4  
- `handle`: 8

#### 2.2 **Validation**

- ✅ Exactly one base  
- ✅ Each door has 1 handle → 4 handles for 4 doors  
- ✅ Each drawer has 1 handle → 4 handles for 4 drawers  
- ✅ No trays → ✓ (not a microwave)  
- ✅ Every handle is attached to a door or drawer (verified using open-state image)

All rules are satisfied.

#### 2.3 **Attachment Inference**

From closed/open-state comparison:

- Each **door** is directly attached to the **base**
- Each **drawer** is mounted to slide out of the **base**
- Each **handle** is on its respective **door** or **drawer**

---

### **3. Connectivity Graph Construction**

Final hierarchical structure:

```json
{
  "base": [
    { "door_1": [ { "handle_1": [] } ] },
    { "door_2": [ { "handle_2": [] } ] },
    { "door_3": [ { "handle_3": [] } ] },
    { "door_4": [ { "handle_4": [] } ] },
    { "drawer_1": [ { "handle_5": [] } ] },
    { "drawer_2": [ { "handle_6": [] } ] },
    { "drawer_3": [ { "handle_7": [] } ] },
    { "drawer_4": [ { "handle_8": [] } ] }
  ]
}
```
"""

answer_2 = """
Thanks for the new image pair! Let's analyze the articulated structure of the **washing machine** based on the provided closed-state and open-state images.

---

### **1. Part Detection**

From the **closed-state image**, validated using the **open-state image**:

- **Base**: 1 main body (the washing machine structure)
- **Door**: 1 circular front-loading door
- **Handle**: Notice that there is no handle attached to the dooor
- **Knob**: 1 control knob on the top of the machine

---

### **2. Step-by-Step Reasoning**

#### 2.1 **Part Listing**

- `base`: 1  
- `door`: 1
- `knob`: 1

#### 2.2 **Validation**

- ✅ Exactly one base
- ✅ No drawers, trays → Valid  
- ✅ Trays not present (correct: not a microwave)  

→ **All structural constraints satisfied**

#### 2.3 **Attachment Inference**

- The **door** is front-mounted and clearly opens via a **hinge** on the left side (from viewer's perspective)
- The **knob** is directly mounted on the **base** (top section)
---

### **3. Connectivity Graph Construction**

```json
{
  "base": [
    { "door": []},
    { "knob": []}
  ]
}
```
"""

answer_3 = """
Thanks! Let’s analyze the articulated structure of this oven using your provided closed and open state images.

---

### ✅ Articulated Object Parsing (Oven)

#### **1. Part Detection**

From the **closed-state** image (with **open-state** verification):

- **base**: 1 (the main oven body)
- **door**: 1 (the front oven door)
- **handle**: 1 (long horizontal handle on the door)

> 🔍 *The 6 small control knobs on top are **ignored** as instructed.*

---

#### **2. Step-by-Step Reasoning**

**2.1 Part Listing:**

- `base`: 1  
- `door`: 1  
- `handle`: 1

**2.2 Validation:**

- ✅ Exactly one base  
- ✅ Door has 1 handle  
- ✅ Handle is attached to the door  
- ✅ No trays (✓ valid for an oven)  
- ✅ No knobs or extra handles beyond what's allowed  

✔ All constraints are satisfied.

**2.3 Attachment Inference:**

- The **door** is bottom-hinged and connected to the **base**
- The **handle** is directly mounted on the door

---

#### **3. Final Connectivity Graph**

```json
{
  "base": [
    { "door": [ { "handle": [] } ] }
  ]
}
```
"""

answer_4 = """
Thanks! Let's now analyze the **wardrobe** based on the closed and open-state images you've provided.

---

### ✅ Articulated Object Parsing – Wardrobe

---

### **1. Part Detection**

- **Base**: 1 (entire wardrobe structure)
- **Doors**: 4 vertical panels (two left, two right)
- **Drawers**: 4 horizontal drawers at the bottom
- **Handles**: 8 in total  
  - 4 for doors (1 each)  
  - 4 for drawers (1 each)

---

### **2. Step-by-Step Reasoning**

#### **2.1 Part Listing**

- `base`: 1  
- `door`: 4  
- `drawer`: 4  
- `handle`: 8

#### **2.2 Validation**

- ✅ Exactly one base  
- ✅ Each door has 1 handle → valid  
- ✅ Each drawer has 1 handle → valid  
- ✅ No trays → ✓ valid (not a microwave)  
- ✅ Every handle is attached to a door or drawer (confirmed via open-state image)

✔ All structural rules are satisfied.

---

#### **2.3 Attachment Inference**

- Each **door** is hinged to the **base**
- Each **drawer** slides out of the **base**
- Each **handle** is mounted on one **door** or **drawer**

---

### **3. Final Connectivity Graph**

```json
{
  "base": [
    { "door_1": [ { "handle_1": [] } ] },
    { "door_2": [ { "handle_2": [] } ] },
    { "door_3": [ { "handle_3": [] } ] },
    { "door_4": [ { "handle_4": [] } ] },
    { "drawer_1": [ { "handle_5": [] } ] },
    { "drawer_2": [ { "handle_6": [] } ] },
    { "drawer_3": [ { "handle_7": [] } ] },
    { "drawer_4": [ { "handle_8": [] } ] }
  ]
}
```
"""

answer_all = [answer_sys, answer_1, answer_2, answer_3, answer_4]
messages = [
    {"role": "user", "content": system_prompt},
    {"role": "assistant", "content": answer_sys}
]

for i in range(4):
    root_path = './scripts/imgs_reference/'
    close_path = os.path.join(root_path, f'close{i + 1}.png')
    open_path = os.path.join(root_path, f'open{i + 1}.png')
    close_img = encode_image(close_path, center_crop=False)
    open_img = encode_image(open_path, center_crop=False)
    messages.append(
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/png;base64,{close_img}"},
                },
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/png;base64,{open_img}"},
                }
            ],
        }
    )
    messages.append({"role": "assistant", "content": answer_all[i + 1]})