2025, Oct 18 18:31

ChArUco बोर्ड के लिए सही 1D मार्कर IDs: 2D ग्रिड से क्रैश बचाएं

ChArUco बोर्ड बनाते समय segmentation error से बचें: OpenCV में 2D id_grid की जगह सफेद खानों के लिए 1D मार्कर IDs दें. कारण, सही गणना और काम करने वाला कोड.

कस्टम मार्कर आईडी के साथ ChArUco बोर्ड बनाते हुए, अक्सर लोग शतरंज-बोर्ड जैसी आईडी की ग्रिड दे देते हैं। यही कदम बोर्ड बनाते समय अक्सर segmentation error तक पहुँचा देता है। असल कारण थोड़ा पेचीदा दिखता है, पर सरल है: ChArUco हर सफेद खाने में एक-एक मार्कर रखता है, न कि हर इंटरसेक्शन या हर सेल पर।

समस्या का विवरण

बोर्ड को अंदरूनी ग्रिड आकार से निकाली गई आईडी की 2D array से initialize किया जाता है; पहली नजर में यह उचित लगता है, लेकिन ChArUco की अपेक्षा से मेल नहीं खाता।

def __init__(self, cols=11, rows=8, sq_len=0.015, tag_len=0.011, aruco_set=cv2.aruco.DICT_5X5_250, first_id=0):
    self.cols = cols
    self.rows = rows
    self.sq_len = sq_len
    self.tag_len = tag_len
    self.dict_obj = cv2.aruco.getPredefinedDictionary(aruco_set)
    self.first_id = first_id
    inner_x = cols - 1
    inner_y = rows - 1
    total_tags = inner_x * inner_y
    if first_id + total_tags > self.dict_obj.bytesList.shape[0]:
        raise ValueError(f"Not enough markers in dictionary for board (required: {total_tags})")
    id_grid = np.arange(first_id, first_id + total_tags, dtype=np.int32).reshape(inner_y, inner_x)
    self.board = cv2.aruco.CharucoBoard(
        (self.cols, self.rows),
        self.sq_len,
        self.tag_len,
        self.dict_obj,
        id_grid
    )

इसी id_grid के साथ बोर्ड बनाते समय, ऊपर दिए गए डिफ़ॉल्ट आर्गुमेंट्स के बावजूद भी segmentation error से क्रैश हो सकता है।

क्रैश क्यों होता है

ChArUco बोर्ड शतरंज की बिसात के केवल सफेद खानों के भीतर ArUco मार्कर रखता है। इसलिए ids array में हर सफेद खाने के लिए एक-एक आईडी होनी चाहिए—कोनों या कोशिकाओं के लिए 2D ग्रिड नहीं। OpenCV का विवरण इस लेआउट के बारे में स्पष्ट है:

ChArUco बोर्ड एक सपाट शतरंज-बोर्ड है जिसमें मार्कर शतरंज-बोर्ड के सफेद खानों के अंदर लगाए जाते हैं।

सीधी बात: सफेद खानों की गिनती से ज्यादा आईडी वाली 2D array देने पर आंतरिक अपेक्षाएँ मेल नहीं खातीं और वही क्रैश दिखाई देता है। सही इनपुट एक 1D array है, जिसकी लंबाई दिए गए बोर्ड आकार के सफेद खानों की संख्या के बराबर हो।

कारगर तरीका

उपाय यह है कि पहले सफेद खानों की संख्या निकालें और उतनी ही पोज़िशनों के लिए एक सपाट (1D) आईडी अनुक्रम दें। पूर्णांक विभाजन से सम और विषम दोनों आकारों पर सही गिनती मिल जाती है। सम आकार में सफेद और काले खाने बराबर होते हैं। विषम×विषम आकार में ChArUco बोर्ड के कोने काले होते हैं, इसलिए सफेद खाने काले से एक कम होते हैं—और integer division प्राकृतिक रूप से नीचे की ओर गोल कर वही सही संख्या देता है।

import cv2
import numpy as np
cols = 11
rows = 8
cell_size = 0.015
aruco_size = 0.011
dict_kind = cv2.aruco.DICT_5X5_250
base_id = 0
white_count = (cols * rows) // 2
ids = np.arange(base_id, base_id + white_count)
board_obj = cv2.aruco.CharucoBoard(
    (cols, rows),
    cell_size,
    aruco_size,
    cv2.aruco.getPredefinedDictionary(dict_kind),
    ids
)
img = board_obj.generateImage((1000, 1000), None, 0, 1)
cv2.imshow("charuco", img)
cv2.waitKey(0)

यह एक वैध ChArUco बोर्ड इमेज बनाता है। यदि आपको यह भी सुनिश्चित करना है कि चुनी गई डिक्शनरी में पर्याप्त मार्कर हों, तो अपने मूल लॉजिक वाला क्षमता-चेक बनाए रखें, पर उसे सफेद खानों की संख्या पर लागू करें।

यह क्यों महत्वपूर्ण है

सही आईडी अनुक्रम देने से लो-लेवल क्रैश रुकते हैं और वह लंबा डिबगिंग समय बचता है जो शुरुआत में आईडी लेआउट से असंबंधित लगता है। इससे बोर्ड का वर्णन उसी तरीके से मेल खाता है जैसा ChArUco डिटेक्टर आईडी को सफेद खानों से मैप करने की अपेक्षा करता है। अंत में, कई बोर्डों के लिए पुनरुत्पाद्य या ओवरलैप-रहित रेंज चाहिए हों तो आईडी रेंज की योजना भी सरल रहती है।

व्यावहारिक सुझाव

आईडी की 1D array इस्तेमाल करें—हर सफेद खाने के लिए एक—सही संख्या और क्रम में। यह संख्या (cols * rows) // 2 से निकालें। किसी वैरिएबल का नाम dict न रखें, क्योंकि यह Python के बिल्ट-इन dict को शैडो कर देता है; इसकी जगह dict_kind जैसा नाम लें।

निष्कर्ष

ChArUco 2D आईडी ग्रिड स्वीकार नहीं करता। उसे केवल सफेद खानों के अनुरूप एक सपाट सूची चाहिए। सम और विषम दोनों आकारों में सही गिनती पाने के लिए integer division से आईडी बनाएं, उसी गिनती के लिए डिक्शनरी में पर्याप्त मार्कर होने की जाँच करें—और आप segmentation error से छुटकारा पाते हुए बोर्ड जेनरेशन को नियंत्रित और स्पष्ट बनाए रखेंगे।

यह लेख StackOverflow के प्रश्न पर आधारित है, जिसे Tommy Llewellyn ने पूछा था, और simon के उत्तर पर।