1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2024-11-16 20:29:02 +00:00

use rotation as option

This commit is contained in:
Bruno Cabral 2023-07-03 17:01:59 -07:00
parent b00f0bf4f1
commit e12fd54928
9 changed files with 49 additions and 17 deletions

View File

@ -118,7 +118,7 @@ def get_match(first, second, percentage):
return Match(first, second, percentage) return Match(first, second, percentage)
def async_compare(ref_ids, other_ids, dbname, threshold, picinfo): def async_compare(ref_ids, other_ids, dbname, threshold, picinfo, match_rotated=False):
# The list of ids in ref_ids have to be compared to the list of ids in other_ids. other_ids # The list of ids in ref_ids have to be compared to the list of ids in other_ids. other_ids
# can be None. In this case, ref_ids has to be compared with itself # can be None. In this case, ref_ids has to be compared with itself
# picinfo is a dictionary {pic_id: (dimensions, is_ref)} # picinfo is a dictionary {pic_id: (dimensions, is_ref)}
@ -136,27 +136,33 @@ def async_compare(ref_ids, other_ids, dbname, threshold, picinfo):
other_dimensions, other_is_ref = picinfo[other_id] other_dimensions, other_is_ref = picinfo[other_id]
if ref_is_ref and other_is_ref: if ref_is_ref and other_is_ref:
continue continue
if ref_dimensions != other_dimensions:
if match_rotated:
rotated_ref_dimensions = (ref_dimensions[1], ref_dimensions[0]) rotated_ref_dimensions = (ref_dimensions[1], ref_dimensions[0])
if ref_dimensions != other_dimensions and rotated_ref_dimensions != other_dimensions: if rotated_ref_dimensions != other_dimensions:
continue continue
for orientation_ref in range(8): else:
for orientation_other in range(8): continue
orientation_range = 1
if match_rotated:
orientation_range = 8
for orientation_ref in range(orientation_range):
try: try:
diff = avgdiff(ref_blocks[orientation_ref], other_blocks[orientation_other], limit, MIN_ITERATIONS) diff = avgdiff(ref_blocks[orientation_ref], other_blocks[0], limit, MIN_ITERATIONS)
percentage = 100 - diff percentage = 100 - diff
except (DifferentBlockCountError, NoBlocksError): except (DifferentBlockCountError, NoBlocksError):
percentage = 0 percentage = 0
if percentage >= threshold: if percentage >= threshold:
results.append((ref_id, other_id, percentage)) results.append((ref_id, other_id, percentage))
break break
else:
continue
break
cache.close() cache.close()
return results return results
def getmatches(pictures, cache_path, threshold, match_scaled=False, j=job.nulljob): def getmatches(pictures, cache_path, threshold, match_scaled=False, match_rotated=False, j=job.nulljob):
def get_picinfo(p): def get_picinfo(p):
if match_scaled: if match_scaled:
return ((None, None), p.is_ref) return ((None, None), p.is_ref)
@ -211,7 +217,7 @@ def getmatches(pictures, cache_path, threshold, match_scaled=False, j=job.nulljo
picinfo.update({p.cache_id: get_picinfo(p) for p in other_chunk}) picinfo.update({p.cache_id: get_picinfo(p) for p in other_chunk})
else: else:
other_ids = None other_ids = None
args = (ref_ids, other_ids, cache_path, threshold, picinfo) args = (ref_ids, other_ids, cache_path, threshold, picinfo, match_rotated)
async_results.append(pool.apply_async(async_compare, args)) async_results.append(pool.apply_async(async_compare, args))
collect_results() collect_results()
collect_results(collect_all=True) collect_results(collect_all=True)

View File

@ -14,6 +14,7 @@ from core.pe import matchblock, matchexif
class ScannerPE(Scanner): class ScannerPE(Scanner):
cache_path = None cache_path = None
match_scaled = False match_scaled = False
match_rotated = False
@staticmethod @staticmethod
def get_scan_options(): def get_scan_options():
@ -29,6 +30,7 @@ class ScannerPE(Scanner):
cache_path=self.cache_path, cache_path=self.cache_path,
threshold=self.min_match_percentage, threshold=self.min_match_percentage,
match_scaled=self.match_scaled, match_scaled=self.match_scaled,
match_rotated=self.match_rotated,
j=j, j=j,
) )
elif self.scan_type == ScanType.EXIFTIMESTAMP: elif self.scan_type == ScanType.EXIFTIMESTAMP:

View File

@ -14,6 +14,10 @@ Preferences
If you check this box, pictures of different dimensions will be allowed in the same If you check this box, pictures of different dimensions will be allowed in the same
duplicate group. duplicate group.
**Match pictures of different rotations:**
If you check this box, pictures of different rotations will be allowed in the same
duplicate group.
.. _filter-hardness: .. _filter-hardness:
**Filter Hardness:** **Filter Hardness:**

View File

@ -307,6 +307,10 @@ msgstr "Debug mode (restart required)"
msgid "Match pictures of different dimensions" msgid "Match pictures of different dimensions"
msgstr "Match pictures of different dimensions" msgstr "Match pictures of different dimensions"
#: qt/pe/preferences_dialog.py:19 cocoa/en.lproj/Localizable.strings:0
msgid "Match pictures of different rotations"
msgstr "Match pictures of different rotations"
#: qt/preferences_dialog.py:43 #: qt/preferences_dialog.py:43
msgid "Filter Hardness:" msgid "Filter Hardness:"
msgstr "Filter Hardness:" msgstr "Filter Hardness:"

View File

@ -316,6 +316,10 @@ msgstr "Mode de depuración (se requiere reinicio)"
msgid "Match pictures of different dimensions" msgid "Match pictures of different dimensions"
msgstr "Coincidencia de imágenes de distintas dimensiones" msgstr "Coincidencia de imágenes de distintas dimensiones"
#: qt/pe/preferences_dialog.py:19 cocoa/en.lproj/Localizable.strings:0
msgid "Match pictures of different rotations"
msgstr "Coincidencia de imágenes de distintas rotaciones"
#: qt/preferences_dialog.py:43 #: qt/preferences_dialog.py:43
msgid "Filter Hardness:" msgid "Filter Hardness:"
msgstr "Dureza del Filtro:" msgstr "Dureza del Filtro:"

View File

@ -314,6 +314,10 @@ msgstr "Modo de Depuração (requer reinício)"
msgid "Match pictures of different dimensions" msgid "Match pictures of different dimensions"
msgstr "Coincidir fotos de dimensões diferentes" msgstr "Coincidir fotos de dimensões diferentes"
#: qt/pe/preferences_dialog.py:19 cocoa/en.lproj/Localizable.strings:0
msgid "Match pictures of different rotations"
msgstr "Coincidir fotos de rotações diferentes"
#: qt/preferences_dialog.py:43 #: qt/preferences_dialog.py:43
msgid "Filter Hardness:" msgid "Filter Hardness:"
msgstr "Pressão do Filtro:" msgstr "Pressão do Filtro:"

View File

@ -192,6 +192,7 @@ class DupeGuru(QObject):
scanned_tags.add("year") scanned_tags.add("year")
self.model.options["scanned_tags"] = scanned_tags self.model.options["scanned_tags"] = scanned_tags
self.model.options["match_scaled"] = self.prefs.match_scaled self.model.options["match_scaled"] = self.prefs.match_scaled
self.model.options["match_rotated"] = self.prefs.match_rotated
self.model.options["include_exists_check"] = self.prefs.include_exists_check self.model.options["include_exists_check"] = self.prefs.include_exists_check
self.model.options["rehash_ignore_mtime"] = self.prefs.rehash_ignore_mtime self.model.options["rehash_ignore_mtime"] = self.prefs.rehash_ignore_mtime

View File

@ -21,6 +21,8 @@ class PreferencesDialog(PreferencesDialogBase):
self.widgetsVLayout.addLayout(self.filterHardnessHLayout) self.widgetsVLayout.addLayout(self.filterHardnessHLayout)
self._setupAddCheckbox("matchScaledBox", tr("Match pictures of different dimensions")) self._setupAddCheckbox("matchScaledBox", tr("Match pictures of different dimensions"))
self.widgetsVLayout.addWidget(self.matchScaledBox) self.widgetsVLayout.addWidget(self.matchScaledBox)
self._setupAddCheckbox("matchRotatedBox", tr("Match pictures of different rotations"))
self.widgetsVLayout.addWidget(self.matchRotatedBox)
self._setupAddCheckbox("mixFileKindBox", tr("Can mix file kind")) self._setupAddCheckbox("mixFileKindBox", tr("Can mix file kind"))
self.widgetsVLayout.addWidget(self.mixFileKindBox) self.widgetsVLayout.addWidget(self.mixFileKindBox)
self._setupAddCheckbox("useRegexpBox", tr("Use regular expressions when filtering")) self._setupAddCheckbox("useRegexpBox", tr("Use regular expressions when filtering"))
@ -57,6 +59,7 @@ show scrollbars to span the view around"
def _load(self, prefs, setchecked, section): def _load(self, prefs, setchecked, section):
setchecked(self.matchScaledBox, prefs.match_scaled) setchecked(self.matchScaledBox, prefs.match_scaled)
setchecked(self.matchRotatedBox, prefs.match_rotated)
# Update UI state based on selected scan type # Update UI state based on selected scan type
scan_type = prefs.get_scan_type(AppMode.PICTURE) scan_type = prefs.get_scan_type(AppMode.PICTURE)
@ -67,5 +70,6 @@ show scrollbars to span the view around"
def _save(self, prefs, ischecked): def _save(self, prefs, ischecked):
prefs.match_scaled = ischecked(self.matchScaledBox) prefs.match_scaled = ischecked(self.matchScaledBox)
prefs.match_rotated = ischecked(self.matchRotatedBox)
prefs.details_dialog_override_theme_icons = ischecked(self.details_dialog_override_theme_icons) prefs.details_dialog_override_theme_icons = ischecked(self.details_dialog_override_theme_icons)
prefs.details_dialog_viewers_show_scrollbars = ischecked(self.details_dialog_viewers_show_scrollbars) prefs.details_dialog_viewers_show_scrollbars = ischecked(self.details_dialog_viewers_show_scrollbars)

View File

@ -225,6 +225,7 @@ class Preferences(PreferencesBase):
self.scan_tag_genre = get("ScanTagGenre", self.scan_tag_genre) self.scan_tag_genre = get("ScanTagGenre", self.scan_tag_genre)
self.scan_tag_year = get("ScanTagYear", self.scan_tag_year) self.scan_tag_year = get("ScanTagYear", self.scan_tag_year)
self.match_scaled = get("MatchScaled", self.match_scaled) self.match_scaled = get("MatchScaled", self.match_scaled)
self.match_rotated = get("MatchRotated", self.match_rotated)
def reset(self): def reset(self):
self.filter_hardness = 95 self.filter_hardness = 95
@ -277,6 +278,7 @@ class Preferences(PreferencesBase):
self.scan_tag_genre = False self.scan_tag_genre = False
self.scan_tag_year = False self.scan_tag_year = False
self.match_scaled = False self.match_scaled = False
self.match_rotated = False
def _save_values(self, settings): def _save_values(self, settings):
set_ = self.set_value set_ = self.set_value
@ -330,6 +332,7 @@ class Preferences(PreferencesBase):
set_("ScanTagGenre", self.scan_tag_genre) set_("ScanTagGenre", self.scan_tag_genre)
set_("ScanTagYear", self.scan_tag_year) set_("ScanTagYear", self.scan_tag_year)
set_("MatchScaled", self.match_scaled) set_("MatchScaled", self.match_scaled)
set_("MatchRotated", self.match_rotated)
# scan_type is special because we save it immediately when we set it. # scan_type is special because we save it immediately when we set it.
def get_scan_type(self, app_mode): def get_scan_type(self, app_mode):