الكشف عن الصور المكررة من بصماتها الإدراكية
إذا كنت تحسب أصلًا البصمات الإدراكية لصورك، فإن هذه النقطة الطرفية تحوّل تلك القائمة المسطّحة إلى مجموعات من المكررات.
شغّل الأداة مجانًا
ترسل إدخالًا واحدًا لكل صورة — اسمًا وبصمتها، على هيئة سلسلة سداسية عشرية أو سلسلة ثنائية من 0/1 — إضافة إلى أقصى مسافة Hamming بالبتات. كل زوج من البصمات يقع ضمن تلك المسافة يُربط ببعضه، ثم تُدمج الأزواج المترابطة في مجموعات متصلة، بحيث تنهار سلسلة من الصور شبه المتطابقة في عنقود واحد بدلًا من أزواج متداخلة. تسرد النتيجة كل مجموعة مع أعضائها والمسافات الثنائية الداخلية وأكبر مسافة داخل المجموعة، إلى جانب الإجماليات: كم صورة مكررة وكم صورة تبقى فريدة. لا يُرفع أي ملف: البصمات التي تملكها مسبقًا هي كل المدخلات التي تحتاجها.
من قائمة بصمات إلى مجموعات من المكررات
إن البصمة الإدراكية مثل pHash ذات 64 بتًا تُرمّز مظهر الصورة، لذا فإن صورتين لا تختلفان إلا في الضغط أو الحجم أو علامة مائية تُنتجان بصمتين لا تختلفان إلا في بضع بتات. مقارنة تلك البصمات ثنائيًا أمر سهل؛ أما الجزء المزعج فهو ما يأتي بعد ذلك. الصورة A تطابق B، وB تطابق C، لكن A لا تطابق C تمامًا — فهل هذه مجموعة مكررة واحدة أم اثنتان؟ تحسم هذه القدرة هذا السؤال بالطريقة المعيارية: تعامل كل صورة كعقدة، وترسم ضلعًا بين أي بصمتين تكون مسافة Hamming بينهما على الأكثر مساوية للعتبة التي تختارها، وتُبلغ عن المكوّنات المتصلة بوصفها مجموعات التكرار. تحصل على إدخال واحد لكل مجموعة يتضمن أسماء الأعضاء، وكل زوج ضمن العتبة مع مسافته الدقيقة، وأكبر مسافة داخل المجموعة، بحيث يمكنك تدقيق سبب وقوع صورتين معًا. ولأن التجميع يتم بالتعدّي، فإن سلسلة إعادة حفظ تنحرف بتًا واحدًا في كل مرة تبقى في عنقود واحد، وهذا بالضبط السلوك المتوقع من كشف شبه التكرار في مكتبات الصور الحقيقية.
اختيار العتبة وصيغة البصمة
العتبة هي أقصى مسافة Hamming بالبتات وقيمتها الافتراضية 5، وهي نقطة بداية شائعة للبصمات ذات 64 بتًا: الصور المتطابقة تسجّل 0، وإعادة الترميز التي لا يمكن تمييزها بصريًا تبقى عادة تحت 5. اخفضها نحو 0 عندما تريد التطابقات التامة أو شبه التامة فقط، وارفعها بحذر عندما يغيّر خط معالجتك الأحجام بقوة أو يقصّ الحواف، لأن كل بت تسامح إضافي يضاعف احتمال الإيجابيات الكاذبة في المجموعات الكبيرة. تُقبل البصمات بصيغتين: سلاسل سداسية عشرية تُفكّ بمعدل أربع بتات لكل حرف، أو سلاسل ثنائية حرفية من 0/1. القاعدة الصارمة الوحيدة هي الاتساق — يجب أن تستخدم كل بصمة في الطلب الواحد الصيغة نفسها وأن تُفكّ إلى طول البتات نفسه، وإلا كانت المسافة بينها بلا معنى ويُرفض الطلب بخطأ واضح. كذلك تُرفض العتبة السالبة بوصفها مدخلًا غير صالح. ويمكنك حساب البصمات نفسها بالقدرة الشقيقة image.phash التي تُنتج بالضبط السلاسل السداسية العشرية ذات الأحرف الستة عشر التي تتوقعها هذه النقطة الطرفية.
مخرجات حتمية يمكنك مقارنتها وتخزينها
صُمّمت الاستجابة لتُخزَّن بجانب فهرسك وتُقارَن عبر الزمن. تُرتَّب المجموعات بحسب موضع أقدم عضو فيها في قائمة الإدخال، ويحتفظ الأعضاء بترتيب الإدخال، وتُدرج الأزواج الداخلية بالاسمين والمسافة الدقيقة، بحيث ينتج تشغيلان على القائمة نفسها مخرجات متطابقة بايتًا ببايت وتظهر التراجعات كفروقات نظيفة. إلى جانب المجموعات تحصل على العدّادات التي تحتاجها لوحات المتابعة: إجمالي الصور المعالَجة، وطول بتات البصمات، وعدد مجموعات التكرار، وكم صورة تقع داخل أي مجموعة، وكم صورة تبقى فريدة. لا عشوائية ولا ساعة ولا شبكة: المدخلات نفسها تُعطي دائمًا الإجابة نفسها، في API وفي المشغّل المجاني بالمتصفح في هذه الصفحة الذي ينفّذ الشيفرة نفسها تمامًا. وهذا يجعلها آمنة للاستخدام في مسارات CI التي تُفشل البناء عندما تتسلل مكررات جديدة إلى مستودع الأصول، وفي مهام التنظيف المجدولة التي ترسل تقرير إزالة التكرار بالبريد الإلكتروني.
حالات الاستخدام
إزالة التكرار من فهرس منتجات
أدخل بصمات pHash لكل صور المنتجات وادمج القوائم التي تعيد استخدام الصورة نفسها بأسماء ملفات أو أحجام مختلفة.
تدقيق مكتبة صور جاهزة
اعثر على اللقطات شبه المتطابقة من الجلسة نفسها ليحتفظ المراجعون بممثل واحد بدلًا من اثنتي عشرة نسخة معاد تصديرها.
حراسة خط رفع الملفات
ارفض أو علّم أي رفع جديد عندما تقع بصمته ضمن العتبة من صورة تخزّنها مسبقًا.
الأسئلة الشائعة
كم تبلغ التكلفة؟
$0.002 لكل طلب. وهي مجانية أيضًا للتشغيل في متصفحك على هذه الصفحة بالشيفرة نفسها.
هل أرفع الصور نفسها؟
لا. ترسل فقط البصمات الإدراكية التي حسبتها مسبقًا، مع اسم لكل صورة. الملفات الثنائية لا تغادر جهازك أبدًا.
ما صيغ البصمات المقبولة؟
السلاسل السداسية العشرية (أربع بتات لكل حرف، ولا فرق بين الأحرف الكبيرة والصغيرة) والسلاسل الثنائية الحرفية من 0/1. يجب أن تتشارك كل البصمات في الطلب الواحد الصيغة نفسها وطول البتات نفسه.
ما العتبة التي ينبغي أن أستخدمها؟
القيمة الافتراضية هي 5 بتات، وهي نقطة بداية معقولة لبصمات pHash ذات 64 بتًا. استخدم 0 للتطابقات التامة فقط وارفعها بحذر: القيم الأعلى تلتقط مزيدًا من نسخ إعادة الحفظ لكن أيضًا مزيدًا من الإيجابيات الكاذبة.
كيف تُشكَّل المجموعات عندما تتداخل التطابقات؟
عن طريق المكوّنات المتصلة: إذا طابقت A صورة B وطابقت B صورة C ضمن العتبة، تقع الثلاث كلها في مجموعة واحدة حتى لو كانت A وC أبعد من العتبة. تُدرج المسافات الثنائية الدقيقة لتتمكن من تدقيق كل رابط.
ماذا يحدث مع عتبة سالبة؟
يُرفض الطلب بوصفه مدخلًا غير صالح، لأن مسافة Hamming لا يمكن أن تكون سالبة، ولا تُخصم منك أي رسوم.
للمطوّرين — الوصول عبر API
كل ما في هذه الصفحة متاح برمجيًا. هذا القسم موجّه للفرق التقنية التي تريد ربط الأداة بأنظمتها الخاصة؛ بقية المستخدمين يمكنهم استخدام الأداة أعلاه مباشرة دون الحاجة لقراءة ما يلي.
الـEndpoint
صادِق على طلبك بترويسة Bearer، وأرسل طلب POST واحدًا لتدخل مهمتك قائمة التنفيذ فورًا؛ ثم تستلم النتيجة عبر webhook أو رابط موقّع.
استدعِ الخدمة من بيئتك
curl -X POST https://api.kit.forhosting.com/image/duplicate-detect-hash \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"images":[{"name":"hero-a.jpg","hash":"ff8f8383c3c3c3ff"},{"name":"hero-b.jpg","hash":"ff8f8383c3c3c3f7"},{"name":"hero-c.jpg","hash":"ff8f8383c3c3c3f3"},{"name":"logo.png","hash":"007c7c7c7c7c7c00"}]}'const res = await fetch("https://api.kit.forhosting.com/image/duplicate-detect-hash", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"images": [
{
"name": "hero-a.jpg",
"hash": "ff8f8383c3c3c3ff"
},
{
"name": "hero-b.jpg",
"hash": "ff8f8383c3c3c3f7"
},
{
"name": "hero-c.jpg",
"hash": "ff8f8383c3c3c3f3"
},
{
"name": "logo.png",
"hash": "007c7c7c7c7c7c00"
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/image/duplicate-detect-hash",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"images": [
{
"name": "hero-a.jpg",
"hash": "ff8f8383c3c3c3ff"
},
{
"name": "hero-b.jpg",
"hash": "ff8f8383c3c3c3f7"
},
{
"name": "hero-c.jpg",
"hash": "ff8f8383c3c3c3f3"
},
{
"name": "logo.png",
"hash": "007c7c7c7c7c7c00"
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/image/duplicate-detect-hash", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"images":[{"name":"hero-a.jpg","hash":"ff8f8383c3c3c3ff"},{"name":"hero-b.jpg","hash":"ff8f8383c3c3c3f7"},{"name":"hero-c.jpg","hash":"ff8f8383c3c3c3f3"},{"name":"logo.png","hash":"007c7c7c7c7c7c00"}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"images":[{"name":"hero-a.jpg","hash":"ff8f8383c3c3c3ff"},{"name":"hero-b.jpg","hash":"ff8f8383c3c3c3f7"},{"name":"hero-c.jpg","hash":"ff8f8383c3c3c3f3"},{"name":"logo.png","hash":"007c7c7c7c7c7c00"}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/image/duplicate-detect-hash", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)مثال على الطلب
{
"images": [
{
"name": "hero-a.jpg",
"hash": "ff8f8383c3c3c3ff"
},
{
"name": "hero-b.jpg",
"hash": "ff8f8383c3c3c3f7"
},
{
"name": "hero-c.jpg",
"hash": "ff8f8383c3c3c3f3"
},
{
"name": "logo.png",
"hash": "007c7c7c7c7c7c00"
}
]
}مثال على الاستجابة
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "image.duplicate_detect_hash",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}الواجهة غير متزامنة: تستلم task_id فور الإرسال، ويمكنك الاستعلام عن الحالة بمعدل طلب واحد في الثانية.
الأسعار
السعر معلن كما تراه: لا tokens ولا نظام نقاط؛ وإن فشلت المهمة فلن تُحاسَب عليها.
الحدود
max_items | 5000 |
الأخطاء
| HTTP | الرمز | المعنى |
|---|---|---|
401 | unauthorized | مفتاح الوصول مفقود أو غير صالح؛ تحقق من ترويسة Bearer في طلبك. |
402 | insufficient_balance | رصيدك لا يكفي لتنفيذ هذه المهمة؛ أعد شحن الرصيد ثم أعد المحاولة. |
404 | unknown_type | نوع المهمة المطلوب غير موجود في الكتالوج — راجع الاسم المرسل في الطلب. |
429 | rate_limited | تجاوزت الحد المسموح من الطلبات؛ انتظر قليلًا ثم أعد المحاولة. |