-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathImageEditor.py
More file actions
227 lines (171 loc) · 6.26 KB
/
Copy pathImageEditor.py
File metadata and controls
227 lines (171 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/usr/bin/env python
from PIL import Image, ImageFilter, ImageEnhance
from numpy import asarray
from tkinter import filedialog
def rotateLeft(image: Image.Image) -> Image.Image:
"""
- Counter-clockwise rotation by 90 degrees
"""
if not image: return
return image.rotate(angle=90, expand=True)
def rotateRight(image: Image.Image) -> Image.Image:
"""
- Clockwise rotation by 90 degrees
"""
if not image: return
return image.rotate(angle=-90, expand=True)
def flipHorizontal(image: Image.Image) -> Image.Image:
"""
- Left to Right Flip
"""
if not image: return
return image.transpose(Image.Transpose.TRANSPOSE.FLIP_LEFT_RIGHT)
def flipVertical(image: Image.Image) -> Image.Image:
"""
- Top to Bottom Flip
"""
if not image: return
return image.transpose(Image.Transpose.TRANSPOSE.FLIP_TOP_BOTTOM)
def cropImage(image: Image.Image, startX: int, startY: int, endX: int, endy: int) -> Image.Image:
"""
Cropping the image after truncating the rectangle to be inside the image
"""
if not image: return
# truncating crop going outside the image
width, height = image.size
startX, endX = max(startX, 0), min(endX, width)
startY, endY = max(startY, 0), min(endY, height)
return image.crop((startX, startY, endX, endY))
def redChannel(image: Image.Image) -> Image.Image:
"""
Shows the red value of all the image pixels
"""
if not image: return
image = image.copy()
red = image.convert("RGB").getdata(0)
red = [ (r, 0, 0) for r in red ]
image.putdata(red)
return image
def greenChannel(image: Image.Image) -> Image.Image:
"""
Shows the green value of all the image pixels
"""
if not image: return
image = image.copy()
green = image.convert("RGB").getdata(1)
green = [ (0, g, 0) for g in green ]
image.putdata(green)
return image
def blueChannel(image: Image.Image) -> Image.Image:
"""
Shows the blue value of all the image pixels
"""
if not image: return
image = image.copy()
blue = image.convert("RGB").getdata(2)
blue = [ (0, 0, b) for b in blue ]
image.putdata(blue)
return image
def negative(image: Image.Image) -> Image.Image:
"""
Inverts Image. Subtracting each pixel value from white pixel
"""
if not image: return
return image.convert("RGB").point(lambda x: 255-x)
def blackWhite(image: Image.Image) -> Image.Image:
"""
Gray-Scal conversion
"""
if not image: return
return image.convert("L")
def detectEdge(image: Image.Image) -> Image.Image:
"""
Detects and displays the edges of the image.
Sharper the edge, more visibility it will have in the output.
"""
if not image: return
return image.filter(ImageFilter.FIND_EDGES)
def enhanceEdge(image: Image.Image) -> Image.Image:
"""
Enhances the contrast around the edges of the image to show them more distinctly.
"""
if not image: return
return image.filter(ImageFilter.EDGE_ENHANCE_MORE)
def sketch(image: Image.Image) -> Image.Image:
"""
Converts the iamge into a pencil sketch type look
"""
if not image: return
img_gray = image.convert("L")
img_smooth = img_gray.filter(ImageFilter.GaussianBlur(150))
try: # To suppress RunTimeWarning of divide by zero, and Invalid Value encountered
final = asarray(img_gray) / asarray(img_smooth) * 256.0
except Exception:
pass
return Image.fromarray(final)
def thresholding(image: Image.Image, threshold: int) -> Image.Image:
"""
Sets each pixel to either minimum value or maximum value depending if pixel is less than or greater than threshold respectively
"""
if not image: return
return image.point(lambda x: 256 if x >= threshold else 0)
def erosion(image: Image.Image) -> Image.Image:
"""
Decreases the brightness of the image
"""
if not image: return
return image.filter(ImageFilter.MinFilter(3))
def dilation(image: Image.Image) -> Image.Image:
"""
Decreases the darkness of the image
"""
if not image: return
return image.filter(ImageFilter.MaxFilter(3))
def blurImage(image: Image.Image, value: int) -> Image.Image:
if not image: return
return image.filter(ImageFilter.GaussianBlur(value))
def sharpenImage(image: Image.Image, value: int) -> Image.Image:
if not image: return
return ImageEnhance.Sharpness(image).enhance(value)
def brightenImage(image: Image.Image, value: float) -> Image.Image:
if not image: return
return ImageEnhance.Brightness(image).enhance(value)
def saturateImage(image: Image.Image, value: float) -> Image.Image:
if not image: return
return ImageEnhance.Color(image).enhance(value)
def contrastImage(image: Image.Image, value: float) -> Image.Image:
if not image: return
return ImageEnhance.Contrast(image).enhance(value)
def resizeImage(image: Image.Image, size: tuple[int,int]) -> Image.Image:
try:
if not image: return
image = image.resize(size)
except:
pass
return image
def saveAsImage(image: Image.Image, destinationFile: str) -> str:
"""
- Asks user to select the destination for saving the "image" with user-selected extension.
- Overwrite confirmation by user required.
"""
if not image: return
filename = filedialog.asksaveasfilename(confirmoverwrite=True)
if not filename: # filename invalid
return
extension = destinationFile.split('.')[-1] # destination file extension
if len(filename.split('.')) > 1: # must have name + extension
image.save(fp=filename)
return filename
else: # only name so auto append extension
image.save(fp=filename + '.' + extension)
return filename + '.' + extension
def saveImage(image: Image.Image, destinationFile: str) -> str:
"""
- Saves image overwriting the last saved image location (destinationFile).
- The first saveImage call for the given image has destinationFile as None and so defaults to saveAsImage call.
"""
if image:
if destinationFile:
image.save(fp=destinationFile)
else:
return saveAsImage(image, ".png")