Pergunta

Estou desenvolvendo um aplicativo gráfico usando o QT 4.5 e estou colocando imagens no qpixmapcache, eu queria otimizar isso para que, se um usuário insira uma imagem que já estiver no cache, ela usará isso.

No momento, cada imagem tem um ID exclusivo que ajuda a se otimizar em eventos de pintura. No entanto, percebo que, se eu pudesse calcular um hash da imagem, eu poderia procurar o cache para ver se já existe e usá -lo (ajudaria mais para objetos duplicados, é claro).

Meu problema é que, se é um grande qpixmap, um cálculo de hash desacelerará as coisas ou há uma maneira mais rápida?

Foi útil?

Solução

Alguns comentários sobre isso:

  1. Se você vai gerar uma chave de hash/cache de um pixmap, pode querer pular o qpixmapcache e Use Qcache diretamente. Isso eliminaria algumas despesas gerais de uso do QStrings como chaves (a menos que você também queira usar o caminho do arquivo para localizar os itens)

  2. A partir de qt4.4, o qpixmap tem um valor de "hash" associado a ele (ver Qpixmap :: cachekey () ). A documentação afirma que "objetos qpixmap distintos podem ter apenas a mesma tecla de cache se se referirem ao mesmo conteúdo". No entanto, como o QT usa cópia de dados compartilhados, isso pode se aplicar apenas aos pixmaps copiados e não a dois pixmaps distintos carregados da mesma imagem. Um pouco de teste diria se funciona e, se o fizesse, isso permitiria que você obtenha um valor de hash facilmente.

  3. Se você realmente quer fazer um cache bom e bastante rápido com a remoção de duplicações, Você pode querer olhar para sua própria estrutura de dados Isso classifica de acordo com tamanhos, profundidades de cores, tipos de imagem e coisas como esse. Então você precisaria apenas hash os dados da imagem reais depois de encontrar o mesmo tipo de imagem com as mesmas dimensões, profundidades de bits, etc. É claro que, se seus usuários geralmente abrem muitas imagens com essas coisas iguais, isso não seria 'T ajuda em tudo.

  4. Desempenho: não se esqueça do material de benchmarking QT adicionado em 4.5, o que permitiria comparar suas várias idéias de hash e ver qual é o mais rápido. Ainda não verifiquei, mas parece muito legal.

Outras dicas

Caso alguém se depare com esse problema (e não tem muita experiência com as coisas de hash, principalmente algo como uma imagem), aqui está uma solução muito simples que eu usei para hash de qpixmaps e inseri -los em uma tabela de pesquisa para comparação posterior:

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;
}

Aqui está a própria função de hash (você pode tê -lo hash em um QINT64 se desejar menos colisões). Como você pode ver, converto o Pixmap em um Qimage, e simplesmente percorro suas dimensões e realizo um hash de uma vez por dia em cada pixel e retorno o resultado final. Existem muitas maneiras de melhorar essa implementação (consulte as outras respostas para esta pergunta), mas essa é a essência básica do que precisa ser feito.

O OP mencionou como ele usaria essa função de hash para construir uma tabela de pesquisa para comparar posterior imagens. Isso exigiria uma função de inicialização de pesquisa muito simples - algo assim:

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...
}

Estou usando um QMAP aqui chamado ImageTable, que precisaria ser declarado na classe como tal:

QMap<qint32, QString> imageTable;

Então, finalmente, quando você deseja comparar uma imagem com as imagens em sua tabela de pesquisa (ou seja: "Que imagem, das imagens que eu sei que pode ser, é essa imagem em particular?"), Você apenas chama a função de hash em A imagem (que estou assumindo também será um QPIXMAP) e o valor QString de retorno permitirá que você descubra isso. Algo assim funcionaria:

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.
}

É isso. Espero que isso ajude alguém - isso me salvou algum tempo, embora eu estivesse feliz por ter a experiência de descobrir isso.

Os cálculos de hash devem ser bem rápidos (em algum lugar acima de 100 MB/s, se não houver E/S de disco envolvido), dependendo do algoritmo que você usa. Antes de hash, você também pode fazer alguns testes rápidos para resolver possíveis candidatos - as imagens de FE devem ter a mesma largura e altura, caso contrário, é inútil comparar seus valores de hash.

Obviamente, você também deve manter os valores de hash para imagens inseridas, portanto, você só precisa calcular um hash para novas imagens e não precisará calculá -lo novamente para as imagens em cache.

Se as imagens forem diferentes o suficiente, talvez seja suficiente não hash a imagem inteira, mas uma miniatura menor ou uma parte da imagem (FE First e Last 10 Lines), isso será mais rápido, mas levará a mais colisões.

Suponho que você esteja falando sobre o cálculo de um hash sobre os dados da imagem, em vez de obter o ID exclusivo gerado pelo QT.
Dependendo das suas imagens, você provavelmente não precisa passar por toda a imagem para calcular um hash. Talvez apenas leia os primeiros 10 pixels? Primeira linha de varredura?
Talvez uma pseudo seleção aleatória de pixels de toda a imagem? (com uma semente conhecida para que você possa repetir a sequência) Não se esqueça de adicionar o tamanho da imagem ao hash.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top