مقال
كيف أوقفت اختبارات لقطات الشاشة عن الإنذارات الكاذبة
في Digital Turbine بنيت بـ Java، بمساعدة أدوات البرمجة بالذكاء الاصطناعي، أداة Visual Regression تقارن Perceptual Hashes بدلًا من البكسلات. قلّلت الإخفاقات غير المستقرة في اختبارات لقطات الشاشة. إليك كيف تعمل، ولماذا فشل الحل البديهي أولًا.
مرّر المؤشر لإعادة التشغيل. الفروق الصغيرة تمر، والتغيير الحقيقي يُعلَّم.
لماذا فشلت مقارنة البكسلات
النسخة الأولى فعلت ما تفعله معظم اختبارات لقطات الشاشة: لقطة مرجعية، ولقطة جديدة، وفشل إذا اختلف أي بكسل. في منتج موبايل حقيقي هذا أشبه برمي عملة. الخطوط تُنعَّم بشكل مختلف قليلًا بين التشغيلات، والأجهزة وبرامج تشغيل الرسوميات تقرّب الألوان بشكل مختلف، والشريط المتحرك أو المؤشر الوامض لا يظهران في الإطار نفسه مرتين.
كل واحد من هذه أنتج بناءً أحمر دون أن يكون شيء معطلًا فعلًا. وبعد عدد كافٍ منها، يتوقف الناس عن قراءة الإخفاقات، فتمرّ معها أخطاء الانحدار الحقيقية أيضًا. الاختبار الذي يفشل بسبب الضجيج أسوأ من عدم وجود اختبار.
قارن كيف تبدو الشاشة، لا بكسلاتها
الـ Perceptual Hash بصمة قصيرة لكيف تبدو الصورة للإنسان. تصغّر لقطة الشاشة حتى تختفي التفاصيل الدقيقة، وتزيل الألوان، وتُبقي البنية العامة فقط: أين الفاتح وأين الداكن. تتحول هذه البنية إلى رقم من 64 بت. لقطتان تبدوان متطابقتين للعين البشرية تنتجان الرقم نفسه أو ما يقاربه، حتى لو اختلفت آلاف البكسلات المنفردة.
Hamming Distance هي الحَكَم
لمقارنة بصمتين تعدّ كم بتًا يختلف، وهذه هي Hamming Distance. ضجيج تنعيم الحواف يقلب بتًا أو اثنين. زر مفقود أو تخطيط مكسور أو شاشة خاطئة تقلب الكثير. لذلك ينجح الاختبار حين تكون المسافة تحت العتبة ويفشل حين تتجاوزها، وهذه العتبة هي المفتاح الذي يفصل الضجيج عن التغيير الحقيقي.
// Simplified sketch of the idea, not the production code.
long hash(BufferedImage img) {
// 1. Shrink and drop colour: tiny details and anti-aliasing disappear.
double[][] px = grayscale(resize(img, 32, 32));
// 2. Keep only the low frequencies: the overall shape of the screen.
double[][] freq = dct(px); // top-left 8x8 block
double median = median(topLeft(freq, 8));
// 3. One bit per frequency: above or below the median.
long bits = 0;
for (int i = 0; i < 64; i++) {
bits = (bits << 1) | (topLeft(freq, 8)[i / 8][i % 8] > median ? 1 : 0);
}
return bits;
}
int distance(long a, long b) {
return Long.bitCount(a ^ b); // Hamming distance: bits that differ
}
boolean looksSame(BufferedImage baseline, BufferedImage actual, int threshold) {
return distance(hash(baseline), hash(actual)) <= threshold;
}ضبط العتبة
منخفضة جدًا فيعود الضجيج، مرتفعة جدًا فتمرّ أخطاء انحدار حقيقية. الطريقة لضبطها هي البيانات: شغّل الحزمة مرات كثيرة على بناء لم يتغير لترى إلى أي حد ينحرف الضجيج، ثم تحقق من أن التغييرات الحقيقية المعروفة تقع أعلى من ذلك بكثير. وحين تستمر شاشة في الفشل لأسباب وجيهة، فهذا خطأ في المنتج يجب تسجيله، لا عتبة يجب رفعها.
ما الذي تغيّر
قلّت الإخفاقات غير المستقرة في اختبارات لقطات الشاشة. والأهم من ذلك أن الاختبار البصري الأحمر عاد ليعني شيئًا، فصار الناس يقرؤون الإخفاقات، وأخطاء الانحدار التي تحدث تُكتشف قبل الإصدار لا بعده.