2009-03-05 6 views
4

Qt 4.5를 사용하는 그래픽 응용 프로그램을 개발 중이며 QPixmapCache에 이미지를 넣고 있습니다. 사용자가 이미 캐시에있는 이미지를 삽입하면이를 사용하도록 최적화하고 싶습니다.QPixmap의 해시를 얻는 가장 좋은 방법은 무엇입니까?

지금은 각 이미지에 고유 한 ID가있어 페인트 이벤트에 최적화되어 있습니다. 그러나 나는 이미지의 해시를 계산할 수 있다면 캐시를 조회하여 이미 존재하는지 확인할 수 있으며이를 사용하면 (물론 복제 객체에 더 많은 도움이 될 것입니다.)

제 QPixmap의 해시 계산이 느려지거나 빠른 방법이있는 경우 제 문제는 무엇입니까?

+0

제목의 오타 (어떻게 될 수 있습니다 ...) :) – claf

답변

3

이에 대한 의견의 몇 가지 : 당신이 픽스맵의 해시/캐시 키를 생성하기 위하여려고하는 경우에, 당신은 QPixmapCache을 건너 뛸 및 사용 QCache 직접

  1. . 이렇게하면 파일 경로를 사용하여 항목을 찾으려는 경우가 아니라면 QString을 키로 사용하는 일부 오버 헤드가 없어집니다.

  2. Qt4.4부터 QPixmap에는 이와 관련된 "해시"값이 있습니다 (QPixmap :: cacheKey()). 문서에서는 "다른 QPixmap 개체는 동일한 내용을 참조하는 경우에만 동일한 캐시 키를 가질 수 있습니다."라고 주장합니다. 그러나 Qt는 공유 데이터 복사를 사용하기 때문에 복사 한 픽스맵에만 적용 할 수 있고 동일한 이미지에서로드 된 두 개의 별개의 픽스맵에는 적용 할 수 없습니다. 약간의 테스트는 작동하는지 알려주고, 테스트를 수행하면 쉽게 해시 값을 얻을 수 있습니다. 당신이 정말로 제거 중복으로 좋은, 상당히 빠른 캐시를하고 싶은 경우

  3. 당신은 것과 같은 크기, 색 농도, 이미지 유형, 사물에 따라 정렬 자신의 데이터 구조보고 할 수 있습니다 . 그런 다음 동일한 크기, 비트 심도 등으로 동일한 유형의 이미지를 찾은 후에 실제 이미지 데이터를 해시하면됩니다. 물론 사용자가 일반적으로 동일한 이미지를 사용하여 많은 이미지를 열면, 전혀 도움이 안된다.

  4. 성능 : Qt가 4에 추가 한 벤치마킹 정보를 잊지 마세요.5, 다양한 해싱 아이디어를 비교하고 어느 것이 가장 빠르게 실행되는지 볼 수 있습니다. 아직 체크 아웃하지는 않았지만 꽤 깔끔하게 보입니다. 누구든지이 문제를 가로 질러 온다 (너무 끔찍 이미지와 같은 특히 뭔가 해시 것들, 경험되지 않음) 이런 경우에

1

사용하는 알고리즘에 따라 해시 계산이 상당히 빨라야합니다 (디스크 I/O가없는 경우 100MB/s 이상). 해싱을하기 전에 잠정적 인 후보를 분류하기 위해 빠른 테스트를 수행 할 수도 있습니다. 이미지의 너비와 높이가 같아야합니다. 그렇지 않으면 해시 값을 비교할 필요가 없습니다.

물론 삽입 이미지의 해시 값을 유지해야 새 이미지의 해시 값을 계산할 수 있으며 캐시 된 이미지의 해시 값을 다시 계산할 필요가 없습니다.

이미지가 충분히 다른 경우 전체 이미지를 해시하지 않고 이미지의 작은 축소판이나 이미지 (첫 번째 및 마지막 10 번째 줄)를 해싱하지 않으면 충분하지만이 속도는 빠르지 만 더 많은 충돌.

1

QT가 생성 한 고유 ID를 얻는 대신 실제로 이미지의 데이터에 대해 해시를 계산한다고 가정합니다.
이미지에 따라 해시를 계산할 때 전체 이미지를 검토하지 않아도됩니다. 어쩌면 첫 번째 10 픽셀 만 읽을 수 있습니까? 첫 번째 스캔 라인?
아마 전체 이미지에서 픽셀의 의사 임의 선택? (시퀀스를 반복 할 수 있도록 알려진 시드가 있음) 해시에 이미지 크기를 추가하는 것을 잊지 마십시오.

3

, 여기에 내가 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에 해시 할 수 있습니다)입니다. 보시다시피 나는 픽스맵을 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... 
} 

내가 같은 클래스에서 선언 될 필요가 imageTable라고 여기 QMap 사용하고 있습니다

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

그게 전부입니다. 나는 이것이 누군가를 돕기를 바란다 - 나는 그것을 알아낼 수있는 경험을 갖게되어 기뻤지 만, 그것은 나에게 시간을 절약 해 주었을 것이다.

관련 문제