تقسیم بر ۲۵۵ یا ۲۵۶؟ مسئله اینه
خلاصهٔ کاملتر
نویسنده با یه سناریوی ساده شروع میکنه: داری یه برنامهٔ پردازش تصویر مینویسی که عکس رو میگیره، به اعشاری تبدیل میکنه، یه کاری روش انجام میده و دوباره به رنگ ۸ بیتی ذخیرهاش میکنه. سؤال اینه که اون تبدیل اولیهٔ عدد صحیح به اعشاری رو دقیقاً چطوری باید انجام بدی. دو تا روش رایج هست:
# روش استاندارد، تقسیم بر ۲۵۵
pixels = img / 255.0
output = np.trunc(result * 255 + 0.5)
# روش جایگزین، تقسیم بر ۲۵۶
pixels = (img + 0.5) / 256.0
output = np.trunc(result * 256)روش استاندارد عدد ۰ رو به ۰.۰ و ۲۵۵ رو به ۱.۰ مینگاره و همون کاریه که GPUها هم میکنن. روش جایگزین یه بایاس ۰.۵ اضافه میکنه و بر ۲۵۶ تقسیم میکنه، پس عدد ۰ به ۰.۰۰۱۹۵ میره. نویسنده میگه این جایگزین یه دردسر داره: کد پردازشت دیگه نمیتونه بدون دونستن اون ثابت، پیکسل سیاه رو تشخیص بده، در حالی که با روش استاندارد همیشه میتونی فرض کنی سیاه یعنی ۰.۰.
اما چند تا ایراد هم به روش ۲۵۵ گرفته میشه. اول اینکه binهای دو سرِ بازه (۰ و ۲۵۵) عملاً نصف بقیه پهنا دارن؛ یعنی اگه نویز یکنواخت تو بازهٔ [۰،۱] بسازی و گردش کنی، مقدارهای ۰ و ۲۵۵ نصفِ بقیه ظاهر میشن. نویسنده این رو با یه هیستوگرام از یه میلیون عدد تصادفی هم نشون میده. ولی خودش اعتراف میکنه سخته یه مثال واقعی پیدا کنه که این بایاس واقعاً مشکلساز بشه، چون تبدیل رفتوبرگشتی عکس بدون خطا انجام میشه.
ایراد دوم اینه که مقدارهای اعشاری روش استاندارد دقیق نیستن؛ مثلاً ۱۲۸ تقسیم بر ۲۵۵ تقریباً ۰.۵۰۱۹۶۱ میشه ولی ۱۲۸ تقسیم بر ۲۵۶ دقیقاً ۰.۵ هست. اما نویسنده میگه این خطا واقعاً ناچیزه؛ در حد بیت کمارزش یه عدد اعشاری ۳۲ بیتی، یه خطای نسبی حدود ۰.۰۰۰۰۱ درصد که عملاً بیاهمیته و بیشتر یه مسئلهٔ سلیقهایه تا فنی.
بخش جالب مقاله جاییه که نویسنده عقب میکشه و این دو روش رو بهعنوان دو نوع کوانتایزر اسکالر یکنواخت نگاه میکنه. طبق ویکیپدیا دو نوع اصلی کوانتایزر داریم: mid-tread که صفر رو به صفر مینگاره، و mid-riser که صفر رو وسطِ دو عدد صحیح میذاره. از این زاویه، روش استاندارد یه ترکیب عجیب از کوانتایزر mid-riser با L=255 هست که برای ورودی ۸ بیتی بهینه نیست؛ این کار صرفاً برای راحتیِ نگاشتن سرها به ۰.۰ و ۱.۰ انجام میشه.
نکتهٔ کلیدی نتیجهگیری اینه: درسته روش ۲۵۶ از نظر تئوری خطای بازسازی کمتری داره (میانگین خطای مطلق ۱.۱۰۲۴ در برابر ۱.۱۰۲۰)، ولی این مزیت فقط وقتی واقعیه که خودت هم ذخیره و هم بارگذاری رو کنترل کنی. وقتی عکسِ بقیه رو لود میکنی، اطلاعاتی که موقع کوانتایز شدن از دست رفته دیگه برنمیگرده؛ بدتر اینکه چون احتمالاً با روش استاندارد ذخیره شدن، لود کردنشون با روش ۲۵۶ عملاً خطای بیشتری وارد میکنه. به گفتهٔ نویسنده هیچوقت هم نباید مرحلهٔ encode و decode دو کوانتایزر رو قاتی کنی، چون نتیجهش کد خرابه.
نکات کلیدی:
- برای تبدیل رنگ ۸ بیتی به اعشاری دو روش رایجه: تقسیم بر ۲۵۵ (استاندارد) یا بایاس ۰.۵ و تقسیم بر ۲۵۶
- روش ۲۵۵ یه کوانتایزر mid-riser و روش ۲۵۶ یه mid-tread حساب میشه
- خطای دقت روش ۲۵۵ ناچیز و در حد بیت کمارزش عدد اعشاری ۳۲ بیتیه
- مزیت دقت روش ۲۵۶ فقط وقتی واقعیه که خودت هم ذخیره و هم بارگذاری رو کنترل کنی
- اگه عکس دیگرون رو پردازش میکنی، روش ۲۵۵ درسته؛ لود کردنشون با ۲۵۶ خطای بیشتری وارد میکنه




