Skip to content

Commit 2d98030

Browse files
committed
updated dependencies
1 parent 9b8f71f commit 2d98030

File tree

12 files changed

+275
-0
lines changed

12 files changed

+275
-0
lines changed

.pypirc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[distutils]
2+
index-servers =
3+
pypi
4+
5+
[pypi]
6+
username = basil_ahamed
7+
password = pypi-AgEIcHlwaS5vcmcCJDA5YmIwMjcxLTVhNzItNDAxMC04MGNiLTA3YTEyM2Q4Yjg5MAACKlszLCI4NDgxNjI5Yy03Y2Y1LTQ2NDYtOGFhYi05MWEyZjQ3NGJiYTIiXQAABiAd5WwMlEsrSq4957VXv_bE38q2xDyVttVTo-0oqu5yAw

build/lib/visual_comparison/__init__.py

Whitespace-only changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class ImageComparisonException(Exception):
2+
"""
3+
A custom exception class for image comparison failures.
4+
"""
5+
6+
def __init__(self, message, cause=None):
7+
"""
8+
Initializes a new ImageComparisonException with the specified detail message and cause.
9+
10+
:param message: The detail message. The detail message is saved for later retrieval.
11+
:param cause: The cause of the exception (optional).
12+
"""
13+
super().__init__(message)
14+
self.cause = cause
15+
16+
class ImageNotFoundException(Exception):
17+
"""
18+
A custom exception class for image not found errors.
19+
"""
20+
21+
def __init__(self, message):
22+
"""
23+
Initializes a new ImageNotFoundException with the specified detail message.
24+
25+
: param message: The detail message. The detail message is saved for later retrieval.
26+
"""
27+
super().__init__(message)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import cv2
2+
import numpy as np
3+
from visual_comparison.exceptions import ImageComparisonException,ImageNotFoundException
4+
from skimage.metrics import structural_similarity as ssim
5+
6+
class ImageComparisonUtil:
7+
@staticmethod
8+
def read_image(path):
9+
try:
10+
image = cv2.imread(path)
11+
if image is None:
12+
raise ImageNotFoundException(f"Image with path '{path}' not found")
13+
return image
14+
except Exception as e:
15+
raise ImageComparisonException(f"Cannot read image from the file, path={path}", e)
16+
17+
@staticmethod
18+
def save_image(path, image):
19+
try:
20+
cv2.imwrite(path, image)
21+
except Exception as e:
22+
raise ImageComparisonException(f"Cannot save image to path={path}", e)
23+
24+
# show difference as B/W Image
25+
@staticmethod
26+
def compare_images_bw(expected_image, actual_image, result_destination=None):
27+
# Convert images to grayscale
28+
expected_gray = cv2.cvtColor(expected_image, cv2.COLOR_BGR2GRAY)
29+
actual_gray = cv2.cvtColor(actual_image, cv2.COLOR_BGR2GRAY)
30+
31+
# Calculate Structural Similarity Index (SSI)
32+
similarity_index = ssim(expected_gray, actual_gray)
33+
34+
# If result destination is provided, save the difference image
35+
if result_destination:
36+
diff_image = cv2.absdiff(expected_gray, actual_gray)
37+
ImageComparisonUtil.save_image(result_destination, diff_image)
38+
39+
return similarity_index
40+
41+
# show difference as individual red boxes
42+
@staticmethod
43+
def compare_images_sep(expected_image, actual_image, result_destination=None):
44+
# Convert images to grayscale
45+
expected_gray = cv2.cvtColor(expected_image, cv2.COLOR_BGR2GRAY)
46+
actual_gray = cv2.cvtColor(actual_image, cv2.COLOR_BGR2GRAY)
47+
48+
# Calculate Structural Similarity Index (SSI)
49+
similarity_index = ssim(expected_gray, actual_gray)
50+
51+
# If result destination is provided, save the difference image
52+
if result_destination:
53+
# Calculate absolute difference image
54+
diff_image = cv2.absdiff(expected_gray, actual_gray)
55+
56+
# Threshold the difference image
57+
_, thresholded_diff = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY)
58+
59+
# Find contours of differences
60+
contours, _ = cv2.findContours(thresholded_diff, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
61+
62+
# Draw rectangles around differences
63+
for contour in contours:
64+
x, y, w, h = cv2.boundingRect(contour)
65+
cv2.rectangle(actual_image, (x, y), (x + w, y + h), (0, 0, 255), 2) # Red rectangles
66+
67+
# Save the resulting image
68+
cv2.imwrite(result_destination, actual_image)
69+
70+
return similarity_index
71+
72+
# show difference as a complete rectangular box
73+
@staticmethod
74+
def compare_images(expected_image, actual_image, result_destination=None):
75+
# Convert images to grayscale
76+
expected_gray = cv2.cvtColor(expected_image, cv2.COLOR_BGR2GRAY)
77+
actual_gray = cv2.cvtColor(actual_image, cv2.COLOR_BGR2GRAY)
78+
79+
# Calculate Structural Similarity Index (SSI)
80+
similarity_index = ssim(expected_gray, actual_gray)
81+
82+
# If result destination is provided, save the difference image
83+
if result_destination:
84+
# Calculate absolute difference image
85+
diff_image = cv2.absdiff(expected_gray, actual_gray)
86+
87+
# Threshold the difference image
88+
_, thresholded_diff = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY)
89+
90+
# Find contours of differences
91+
contours, _ = cv2.findContours(thresholded_diff, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
92+
93+
# Combine all bounding rectangles into one
94+
combined_rect = cv2.boundingRect(np.concatenate(contours))
95+
x, y, w, h = combined_rect
96+
97+
# Draw a rectangle around the combined differences
98+
cv2.rectangle(actual_image, (x, y), (x + w, y + h), (0, 0, 255), 2) # Red rectangle
99+
100+
# Save the resulting image
101+
cv2.imwrite(result_destination, actual_image)
102+
103+
return similarity_index
104+
105+
@staticmethod
106+
def check_mismatch(expected_image, actual_image):
107+
similarity_index = ImageComparisonUtil.compare_images(expected_image, actual_image)
108+
# If similarity index is less than 1.0, there is a mismatch
109+
if similarity_index < 1.0:
110+
return True
111+
return False
112+
113+
114+
@staticmethod
115+
def check_match(expected_image, actual_image):
116+
similarity_index = ImageComparisonUtil.compare_images(expected_image, actual_image)
117+
# If similarity index is 1.0, images are identical
118+
if similarity_index == 1.0:
119+
return True
120+
return False
4.91 KB
Binary file not shown.
4.9 KB
Binary file not shown.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
Metadata-Version: 2.1
2+
Name: visual-comparison
3+
Version: 1.0.2.7
4+
Summary: Image Comparison Tool
5+
Home-page: https://github.com/BASILAHAMED/visual-comparison
6+
Author: Basil Ahamed
7+
Author-email: [email protected]
8+
License: MIT
9+
Keywords: visual compare image diff testing
10+
Classifier: Intended Audience :: Developers
11+
Classifier: License :: OSI Approved :: MIT License
12+
Classifier: Operating System :: OS Independent
13+
Classifier: Programming Language :: Python
14+
Classifier: Programming Language :: Python :: 3
15+
Classifier: Programming Language :: Python :: 3 :: Only
16+
Classifier: Programming Language :: Python :: 3.8
17+
Classifier: Programming Language :: Python :: 3.9
18+
Classifier: Programming Language :: Python :: 3.10
19+
Description-Content-Type: text/markdown
20+
License-File: LICENSE
21+
Requires-Dist: numpy~=1.26.4
22+
Requires-Dist: opencv-python~=4.9.0.80
23+
Requires-Dist: scikit-image~=0.23.1
24+
25+
![logo-trans](https://github.com/BASILAHAMED/visual-comparison/raw/main/logo.png)
26+
27+
## About
28+
Developed with Python utilizing the OpenCV library, this program compares two images of identical sizes, visually highlighting their differences by drawing red rectangles. Offering flexibility for various automation Quality Assurance (QA) tests, especially visual regression testing.
29+
30+
**Key Features:**
31+
32+
* Utilizes standard Python language and specific modules for implementation.
33+
* Generates an output comprising copies of the 'actual' images, with discrepancies delineated by red rectangles.
34+
* This tool serves as a valuable asset for automated visual regression testing, facilitating precise visual comparisons to ensure the integrity and accuracy of image-based applications.
35+
36+
## Usage
37+
38+
#### Modules Required
39+
```python
40+
numpy
41+
opencv-python
42+
scikit-image
43+
```
44+
45+
## To compare two images through visual-comparison module
46+
47+
#### 1. Sample Code to get Similarity Index:
48+
49+
[Get Similarity Index](https://github.com/BASILAHAMED/visual-comparison/blob/main/get_similarity_index.py)
50+
51+
```python
52+
# Using ImageComparisonUtil to get similarity index and compare output image
53+
# Load images to be compared
54+
expected_image = ImageComparisonUtil.read_image_from_resources("expected.png")
55+
actual_image = ImageComparisonUtil.read_image_from_resources("actual.png")
56+
57+
# Where to save the result
58+
result_destination = "result.png"
59+
60+
# Compare the images and save it as result.png
61+
similarity_index = ImageComparisonUtil.compare_images(expected_image, actual_image, result_destination)
62+
print("Similarity Index:", similarity_index)
63+
```
64+
65+
#### 2. Sample Code to assert match/mismatch:
66+
67+
[Assert Match/Mismatch](https://github.com/BASILAHAMED/visual-comparison/blob/main/asserting_match.py)
68+
69+
```python
70+
# Using ImageComparisonUtil
71+
# Load images to be compared
72+
expected_image = ImageComparisonUtil.read_image_from_resources("expected.png")
73+
actual_image = ImageComparisonUtil.read_image_from_resources("actual.png")
74+
75+
# Asserting both images
76+
match_result = ImageComparisonUtil.check_match(expected_image, actual_image)
77+
assert match_result
78+
```
79+
80+
## Demo
81+
1. Demo shows how **`basic image comparison`** works.
82+
83+
### Expected Image
84+
![expected](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/basic%20comparison/expected.png)
85+
86+
### Actual Image
87+
![actual](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/basic%20comparison/actual.png)
88+
89+
### Result
90+
![result](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/basic%20comparison/result.png)
91+
92+
93+
2. Demo shows how **`colour comparison`** works.
94+
### Expected Image
95+
![expected](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/colour%20comparison/expected.jpg)
96+
97+
### Actual Image
98+
![actual](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/colour%20comparison/actual.png)
99+
100+
### Result
101+
![result](https://github.com/BASILAHAMED/visual-comparison/raw/main/sample_images/colour%20comparison/result.png)
102+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
LICENSE
2+
README.md
3+
setup.py
4+
tests/test_image_comparison.py
5+
visual_comparison/__init__.py
6+
visual_comparison/exceptions.py
7+
visual_comparison/utils.py
8+
visual_comparison.egg-info/PKG-INFO
9+
visual_comparison.egg-info/SOURCES.txt
10+
visual_comparison.egg-info/dependency_links.txt
11+
visual_comparison.egg-info/not-zip-safe
12+
visual_comparison.egg-info/requires.txt
13+
visual_comparison.egg-info/top_level.txt
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)