or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-classes.mdcrop-resistant-hashing.mdhash-conversion.mdhash-generation.mdindex.md

core-classes.mddocs/

0

# Core Classes

1

2

Hash container classes that provide comparison operations, string conversion, and mathematical operations for computing similarity between images. These classes encapsulate hash data and provide the interface for all hash operations.

3

4

## Capabilities

5

6

### ImageHash Class

7

8

Primary hash container for single perceptual hashes with full comparison and serialization support.

9

10

```python { .api }

11

class ImageHash:

12

def __init__(self, binary_array):

13

"""

14

Initialize ImageHash with binary array.

15

16

Args:

17

binary_array (NDArray): Boolean numpy array representing the hash

18

"""

19

20

def __str__(self):

21

"""

22

Convert hash to hexadecimal string representation.

23

24

Returns:

25

str: Hexadecimal string of the hash

26

"""

27

28

def __repr__(self):

29

"""

30

Return string representation of the binary array.

31

32

Returns:

33

str: String representation of hash array

34

"""

35

36

def __sub__(self, other):

37

"""

38

Calculate Hamming distance between two hashes.

39

40

Args:

41

other (ImageHash): Other hash to compare against

42

43

Returns:

44

int: Hamming distance (number of differing bits)

45

46

Raises:

47

TypeError: If other is None or hashes have different shapes

48

"""

49

50

def __eq__(self, other):

51

"""

52

Check if two hashes are equal.

53

54

Args:

55

other (object): Other hash to compare

56

57

Returns:

58

bool: True if hashes are identical

59

"""

60

61

def __ne__(self, other):

62

"""

63

Check if two hashes are not equal.

64

65

Args:

66

other (object): Other hash to compare

67

68

Returns:

69

bool: True if hashes are different

70

"""

71

72

def __hash__(self):

73

"""

74

Return 8-bit integer hash for dictionary keys.

75

76

Returns:

77

int: 8-bit hash value for use as dictionary key

78

"""

79

80

def __len__(self):

81

"""

82

Return bit length of the hash.

83

84

Returns:

85

int: Total number of bits in the hash

86

"""

87

```

88

89

**Usage Example:**

90

91

```python

92

from PIL import Image

93

import imagehash

94

95

# Create hashes

96

image1 = Image.open('photo1.jpg')

97

image2 = Image.open('photo2.jpg')

98

99

hash1 = imagehash.average_hash(image1)

100

hash2 = imagehash.average_hash(image2)

101

102

# Basic operations

103

print(f"Hash 1: {hash1}") # String representation

104

print(f"Hash length: {len(hash1)}") # Bit length (64 for 8x8 hash)

105

106

# Comparison operations

107

distance = hash1 - hash2 # Hamming distance

108

are_equal = hash1 == hash2 # Exact equality

109

are_different = hash1 != hash2 # Inequality

110

111

print(f"Hamming distance: {distance}")

112

print(f"Are equal: {are_equal}")

113

114

# Use as dictionary key

115

hash_dict = {hash1: 'photo1.jpg', hash2: 'photo2.jpg'}

116

filename = hash_dict.get(hash1) # Retrieve using hash as key

117

118

# Hash comparison with tolerance

119

similarity_threshold = 5

120

are_similar = distance < similarity_threshold

121

```

122

123

### ImageMultiHash Class

124

125

Container for multiple hashes used in crop-resistant hashing, with advanced matching capabilities.

126

127

```python { .api }

128

class ImageMultiHash:

129

def __init__(self, hashes):

130

"""

131

Initialize with list of ImageHash objects.

132

133

Args:

134

hashes (list[ImageHash]): List of individual segment hashes

135

"""

136

137

def __eq__(self, other):

138

"""

139

Check equality using matches method.

140

141

Args:

142

other (object): Other multi-hash to compare

143

144

Returns:

145

bool: True if hashes match

146

"""

147

148

def __ne__(self, other):

149

"""

150

Check inequality.

151

152

Args:

153

other (object): Other multi-hash to compare

154

155

Returns:

156

bool: True if hashes don't match

157

"""

158

159

def __sub__(self, other, hamming_cutoff=None, bit_error_rate=None):

160

"""

161

Calculate distance score between multi-hashes.

162

163

Args:

164

other (ImageMultiHash): Other multi-hash to compare

165

hamming_cutoff (float, optional): Maximum hamming distance threshold

166

bit_error_rate (float, optional): Percentage of bits that can differ (default: 0.25)

167

168

Returns:

169

float: Distance score (lower = more similar)

170

"""

171

172

def __hash__(self):

173

"""

174

Return hash of tuple of segment hashes.

175

176

Returns:

177

int: Hash value for dictionary usage

178

"""

179

180

def __str__(self):

181

"""

182

Return comma-separated string of segment hashes.

183

184

Returns:

185

str: Comma-separated hex strings

186

"""

187

188

def __repr__(self):

189

"""

190

Return representation of segment hashes list.

191

192

Returns:

193

str: String representation of hash list

194

"""

195

196

def hash_diff(self, other_hash, hamming_cutoff=None, bit_error_rate=None):

197

"""

198

Get difference metrics between two multi-hashes.

199

200

Args:

201

other_hash (ImageMultiHash): Other multi-hash to compare

202

hamming_cutoff (float, optional): Maximum hamming distance threshold

203

bit_error_rate (float, optional): Bit error rate (default: 0.25)

204

205

Returns:

206

tuple[int, int]: (number_of_matching_segments, sum_of_hamming_distances)

207

"""

208

209

def matches(self, other_hash, region_cutoff=1, hamming_cutoff=None, bit_error_rate=None):

210

"""

211

Check if multi-hash matches another with configurable thresholds.

212

213

Args:

214

other_hash (ImageMultiHash): Other multi-hash to compare

215

region_cutoff (int): Minimum matching regions required (default: 1)

216

hamming_cutoff (float, optional): Maximum hamming distance per region

217

bit_error_rate (float, optional): Bit error rate tolerance (default: 0.25)

218

219

Returns:

220

bool: True if hashes match according to criteria

221

"""

222

223

def best_match(self, other_hashes, hamming_cutoff=None, bit_error_rate=None):

224

"""

225

Find best matching hash from a list of candidates.

226

227

Args:

228

other_hashes (list[ImageMultiHash]): List of candidate hashes

229

hamming_cutoff (float, optional): Maximum hamming distance threshold

230

bit_error_rate (float, optional): Bit error rate tolerance (default: 0.25)

231

232

Returns:

233

ImageMultiHash: Best matching hash from the list

234

"""

235

```

236

237

**Usage Example:**

238

239

```python

240

from PIL import Image

241

import imagehash

242

243

# Create crop-resistant hashes

244

full_image = Image.open('full_photo.jpg')

245

cropped_image = Image.open('cropped_photo.jpg')

246

247

full_hash = imagehash.crop_resistant_hash(full_image)

248

crop_hash = imagehash.crop_resistant_hash(cropped_image)

249

250

# Basic matching

251

matches = full_hash.matches(crop_hash)

252

print(f"Images match: {matches}")

253

254

# Flexible matching with custom thresholds

255

strict_match = full_hash.matches(

256

crop_hash,

257

region_cutoff=2, # Require at least 2 matching regions

258

bit_error_rate=0.15 # Allow 15% bit differences

259

)

260

261

# Get detailed comparison metrics

262

num_matches, total_distance = full_hash.hash_diff(crop_hash)

263

print(f"Matching segments: {num_matches}")

264

print(f"Total distance: {total_distance}")

265

266

# Distance scoring

267

similarity_score = full_hash - crop_hash

268

print(f"Similarity score: {similarity_score}")

269

270

# Find best match from multiple candidates

271

candidates = [

272

imagehash.crop_resistant_hash(Image.open('candidate1.jpg')),

273

imagehash.crop_resistant_hash(Image.open('candidate2.jpg')),

274

imagehash.crop_resistant_hash(Image.open('candidate3.jpg'))

275

]

276

277

best_match = full_hash.best_match(candidates)

278

print(f"Best match: {best_match}")

279

280

# Use as dictionary key

281

multi_hash_dict = {full_hash: 'full_photo.jpg'}

282

```

283

284

## Advanced Usage Patterns

285

286

### Batch Hash Comparison

287

288

```python

289

# Compare one hash against many

290

target_hash = imagehash.average_hash(target_image)

291

image_hashes = [

292

imagehash.average_hash(img) for img in image_list

293

]

294

295

# Find all similar images

296

similar_images = []

297

for i, img_hash in enumerate(image_hashes):

298

distance = target_hash - img_hash

299

if distance < 10: # similarity threshold

300

similar_images.append((i, distance))

301

302

# Sort by similarity

303

similar_images.sort(key=lambda x: x[1])

304

```

305

306

### Hash Tolerance Configuration

307

308

```python

309

# Crop-resistant matching with different tolerance levels

310

strict_tolerance = multi_hash1.matches(

311

multi_hash2,

312

region_cutoff=3, # Need 3+ matching regions

313

bit_error_rate=0.10 # Only 10% bit differences allowed

314

)

315

316

loose_tolerance = multi_hash1.matches(

317

multi_hash2,

318

region_cutoff=1, # Only 1 matching region needed

319

bit_error_rate=0.35 # Allow 35% bit differences

320

)

321

```

322

323

### Custom Hash Functions with Classes

324

325

```python

326

# Create custom hash class wrapper

327

class CustomImageHash(imagehash.ImageHash):

328

def __init__(self, binary_array, metadata=None):

329

super().__init__(binary_array)

330

self.metadata = metadata or {}

331

332

def similarity_percentage(self, other):

333

distance = self - other

334

max_distance = len(self)

335

return (1 - distance / max_distance) * 100

336

337

# Usage

338

custom_hash = CustomImageHash(

339

imagehash.average_hash(image).hash,

340

metadata={'filename': 'image.jpg', 'algorithm': 'average'}

341

)

342

```

343

344

## Error Handling

345

346

```python

347

try:

348

# Hash comparison with error handling

349

distance = hash1 - hash2

350

except TypeError as e:

351

if "must not be None" in str(e):

352

print("One of the hashes is None")

353

elif "same shape" in str(e):

354

print("Hashes have different sizes/shapes")

355

else:

356

raise

357

358

# Safe hash comparison

359

def safe_compare_hashes(hash1, hash2):

360

if hash1 is None or hash2 is None:

361

return None

362

363

try:

364

return hash1 - hash2

365

except TypeError:

366

return None # Incompatible hash types/sizes

367

```