# XXXv2_correct_skew_shadow
```
import numpy as np
import cv2
from skimage.feature import canny
from skimage.transform import hough_line, hough_line_peaks, rotate
from skimage.color import rgb2gray
class SkewDetect:
def __init__(self, input_file=None, sigma=3.0, num_peaks=15):
self.input_file = input_file
self.sigma = sigma
self.num_peaks = num_peaks
def get_max_freq_elem(self, arr):
max_arr = []
freqs = {}
for i in arr:
if i in freqs:
freqs[i] += 1
else:
freqs[i] = 1
sorted_keys = sorted(freqs, key=freqs.get, reverse=True)
max_freq = freqs[sorted_keys[0]]
for k in sorted_keys:
if freqs[k] == max_freq:
max_arr.append(k)
return max_arr
def compare_sum(self, value):
if value >= 44 and value <= 46:
return True
else:
return False
@staticmethod
def calculate_deviation(angle):
angle_in_degrees = np.abs(angle)
deviation = np.abs(np.pi / 4 - angle_in_degrees)
return deviation
def process_single_file(self):
res = self.determine_skew(self.input_file)
return res
def determine_skew(self, img_file):
img = cv2.cvtColor(img_file, cv2.COLOR_BGR2RGB)
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
edges = canny(img, sigma=self.sigma)
h, a, d = hough_line(edges)
_, ap, _ = hough_line_peaks(h, a, d,threshold = 0.25*np.max(h), num_peaks=self.num_peaks)
if len(ap) == 0:
return {"Image File": img_file, "Message": "Bad Quality"}
# absolute_deviations = [self.calculate_deviation(k) for k in ap]
# average_deviation = np.mean(np.rad2deg(absolute_deviations))
# ap_deg = [np.rad2deg(x) for x in ap]
absolute_deviations = []
for k in ap:
slope = np.tan(k)
if abs(slope) > 8:
deviation = self.calculate_deviation(k)
absolute_deviations.append(deviation)
average_deviation = np.mean(np.rad2deg(absolute_deviations))
ap_deg = []
for x in ap:
slope = np.tan(x)
if abs(slope) > 8:
ap_deg.append(np.rad2deg(x))
bin_0_45 = []
bin_45_90 = []
bin_0_45n = []
bin_45_90n = []
for ang in ap_deg:
deviation_sum = int(90 - ang + average_deviation)
if self.compare_sum(deviation_sum):
bin_45_90.append(ang)
continue
deviation_sum = int(ang + average_deviation)
if self.compare_sum(deviation_sum):
bin_0_45.append(ang)
continue
deviation_sum = int(-ang + average_deviation)
if self.compare_sum(deviation_sum):
bin_0_45n.append(ang)
continue
deviation_sum = int(90 + ang + average_deviation)
if self.compare_sum(deviation_sum):
bin_45_90n.append(ang)
angles = [bin_0_45, bin_45_90, bin_0_45n, bin_45_90n]
lmax = 0
for j in range(len(angles)):
l = len(angles[j])
if l >= lmax:
lmax = l
maxi = j
if lmax:
ans_arr = self.get_max_freq_elem(angles[maxi])
ans_res = np.mean(ans_arr)
else:
ans_arr = self.get_max_freq_elem(ap_deg)
ans_res = np.mean(ans_arr)
data = {
"Image File": img_file,
"Average Deviation from pi/4": average_deviation,
"Estimated Angle": ans_res,
"Angle bins": angles}
return data
def shadow(img):
blue,green,red = cv2.split(img)
rgb_planes = [blue,green,red]
result_planes = []
for plane in rgb_planes:
dilated_img = cv2.dilate(plane, np.ones((7,7), np.uint8))
bg_img = cv2.medianBlur(dilated_img, 21)
diff_img = 255 - cv2.absdiff(plane, bg_img)
result_planes.append(diff_img)
result = cv2.merge(result_planes)
return result
def process_image(img):
## shadow
input_img = shadow(img)
## 翻轉
skew_obj = SkewDetect(input_img)
origin_img = cv2.cvtColor(input_img, cv2.COLOR_BGR2RGB)
res = skew_obj.process_single_file()
angle = res['Estimated Angle']
if -45 <= angle <= 90:
rot_angle = angle - 90
elif -90 <= angle < -45:
rot_angle = 90 + angle
else:
rot_angle = angle - 90
rotated = rotate(origin_img, rot_angle, resize=True)
rotated_gray = rgb2gray(rotated)
image_rotated = cv2.cvtColor(np.uint8(rotated_gray * 255), cv2.COLOR_RGB2BGR)
return image_rotated
# if __name__ == '__main__':
# img2=cv2.imread('img2.jpg')
# img3=process_image(img2)
# cv2.imwrite('img3.jpg',img3)
# print('done')
```