سؤال

أقوم بتطوير تطبيق رسومات باستخدام QT 4.5 وأنا أضع الصور في QPixMapCache ، أردت تحسين ذلك بحيث إذا قام المستخدم بإدخال صورة موجودة بالفعل في ذاكرة التخزين المؤقت ، فستستخدم ذلك.

في الوقت الحالي ، تحتوي كل صورة على معرف فريد يساعد على تحسين أحداث الطلاء. ومع ذلك ، أدرك أنه إذا كان بإمكاني حساب تجزئة من الصورة ، فيمكنني البحث عن ذاكرة التخزين المؤقت لمعرفة ما إذا كان موجودًا بالفعل واستخدام ذلك (سيساعد أكثر للكائنات المكررة بالطبع).

مشكلتي هي أنه إذا كان خريطة QPixMap كبيرة ، فهل سيؤدي حساب التجزئة إلى إبطاء الأمور أو هل هناك طريقة أسرع؟

هل كانت مفيدة؟

المحلول

بضع تعليقات على هذا:

  1. إذا كنت ستقوم بإنشاء مفتاح التجزئة/ذاكرة التخزين المؤقت للبيكسل ، فقد ترغب في تخطي QpixMapcache استخدام QCache مباشرة. هذا من شأنه أن يلغي بعض النفقات العامة لاستخدام QStrings كمفاتيح (إلا إذا كنت تريد أيضًا استخدام مسار الملف لتحديد موقع العناصر)

  2. اعتبارًا من QT4.4 ، يحتوي QPixMap على قيمة "التجزئة" المرتبطة به (انظر qpixmap :: cachekey () ). تدعي الوثائق أن "كائنات QPixMap المتميزة يمكن أن تحتوي فقط على مفتاح ذاكرة التخزين المؤقت نفسه إذا كانت تشير إلى نفس المحتويات." ومع ذلك ، نظرًا لأن QT يستخدم نسخ البيانات المشتركة ، فقد ينطبق هذا فقط على خرائط البيكسلات المنسوخة وليس على اثنين من pixmaps متميزين محملة من نفس الصورة. قد يخبرك القليل من الاختبار ما إذا كان يعمل ، وإذا كان الأمر كذلك ، فسيتيح لك الحصول على قيمة تجزئة بسهولة.

  3. إذا كنت ترغب حقًا في القيام بتخزين ذاكرة تخزين مؤقت جيدة وسريعة إلى حد ما مع إزالة الازدواجية ، قد ترغب في إلقاء نظرة على بنية البيانات الخاصة بك هذا النوع وفقًا للأحجام ، وأعماق الألوان ، وأنواع الصور ، وأشياء من هذا القبيل. بعد ذلك ، ستحتاج فقط إلى تجزئة بيانات الصورة الفعلية بعد أن تجد نفس النوع من الصورة بنفس الأبعاد ، والتعمق البت ، وما إلى ذلك. يساعد على الإطلاق.

  4. الأداء: لا تنسى أن الأشياء القياسية التي تمت إضافتها في 4.5 ، مما يتيح لك مقارنة أفكار التجزئة المختلفة ومعرفة أي واحد يدير الأسرع. لم أتحقق من ذلك بعد ، لكنه يبدو أنيقًا جدًا.

نصائح أخرى

فقط في حال واجه أي شخص هذه المشكلة (وليس من ذوي الخبرة بشكل رهيب مع تجزئة الأشياء ، وخاصةً مثل صورة) ، فإليك حلًا بسيطًا جدًا استخدمته في Hashing QPixMaps وإدخالها في جدول بحث للمقارنة لاحقًا:

qint32 HashClass::hashPixmap(QPixmap pix)
{
    QImage image = pix.toImage();
    qint32 hash = 0;

    for(int y = 0; y < image.height(); y++)
    {
        for(int x = 0; x < image.width(); x++)
        {
            QRgb pixel = image.pixel(x,y);

            hash += pixel;
            hash += (hash << 10);
            hash ^= (hash >> 6);
        }
    }

    return hash;
}

فيما يلي وظيفة التجزئة نفسها (يمكنك الحصول على تجزئة في Qint64 إذا كنت ترغب في تصادم أقل). كما ترون ، أقوم بتحويل pixmap إلى Qimage ، وأمشي ببساطة من خلال أبعاده وأداء تجزئة بسيطة جدًا في كل مرة على كل بكسل وإرجاع النتيجة النهائية. هناك العديد من الطرق لتحسين هذا التنفيذ (انظر الإجابات الأخرى على هذا السؤال) ، ولكن هذا هو جوهر ما يجب القيام به.

ذكر OP كيف سيستخدم وظيفة التجزئة هذه لإنشاء جدول بحث لمقارنة الصور لاحقًا. سيتطلب ذلك وظيفة تهيئة بحث بسيطة للغاية - شيء من هذا القبيل:

void HashClass::initializeImageLookupTable()
{
    imageTable.insert(hashPixmap(QPixmap(":/Image_Path1.png")), "ImageKey1");
    imageTable.insert(hashPixmap(QPixmap(":/Image_Path2.png")), "ImageKey2");
    imageTable.insert(hashPixmap(QPixmap(":/Image_Path3.png")), "ImageKey2");
// Etc...
}

أنا أستخدم QMAP هنا يسمى ImeCtable والذي يجب إعلانه في الفصل على هذا النحو:

QMap<qint32, QString> imageTable;

ثم ، أخيرًا ، عندما تريد مقارنة صورة مع الصور الموجودة في جدول البحث الخاص بك (أي: "ما هي الصورة ، من الصور التي أعرف أنها يمكن أن تكون ، هل هذه الصورة بالذات؟") ، يمكنك فقط الاتصال بوظيفة التجزئة الصورة (التي أفترض أنها ستكون أيضًا عبارة عن qpixmap) وستسمح لك قيمة الإرجاع QString بمعرفة ذلك. شيء من هذا القبيل سيعمل:

void HashClass::compareImage(const QPixmap& pixmap)
{
    QString value = imageTable[hashPixmap(pixmap)];
    // Do whatever needs to be done with the QString value and pixmap after this point.
}

هذا هو. آمل أن يساعد هذا شخصًا ما - كان من شأنه أن يوفر لي بعض الوقت ، على الرغم من أنني كنت سعيدًا بتجربة اكتشاف ذلك.

يجب أن تكون حسابات التجزئة سريعة جدًا (في مكان ما فوق 100 ميجابايت/ثانية إذا لم يكن هناك قرص I/O متورط) اعتمادًا على الخوارزمية التي تستخدمها. قبل التجزئة ، يمكنك أيضًا القيام ببعض الاختبارات السريعة لفرز المرشحين المحتملين - يجب أن يكون لعرض FE نفس العرض والارتفاع ، وإلا فإنه لا جدوى من مقارنة قيم التجزئة الخاصة بهم.

بالطبع ، يجب عليك أيضًا الاحتفاظ بقيم التجزئة للصور التي تم إدراجها ، لذا عليك فقط حساب علامة تجزئة للصور الجديدة ولن تضطر إلى حسابها مرة أخرى للصور المخزنة مؤقتًا.

إذا كانت الصور مختلفة بما فيه الكفاية ، فربما يكون ذلك كافياً لعدم تضمين الصورة بأكملها ولكن صورة مصغرة أصغر أو جزءًا من الصورة (FE First and Last 10 Lines) ، سيكون هذا أسرع ، ولكنه سيؤدي إلى مزيد من التصادمات.

أفترض أنك تتحدث عن حساب تجزئة فعليًا على بيانات الصورة بدلاً من الحصول على المعرف الفريد الذي تم إنشاؤه بواسطة QT.
اعتمادًا على صورك ، ربما لا تحتاج إلى الذهاب إلى الصورة بأكملها لحساب تجزئة. ربما اقرأ فقط 10 بكسل؟ خط المسح الأول؟
ربما مجموعة عشوائية زائفة من وحدات البكسل من الصورة بأكملها؟ (مع بذرة معروفة حتى تتمكن من تكرار التسلسل) لا تنسى إضافة حجم الصورة إلى التجزئة أيضًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top