From 0636fc56fd674e01e57c6b83bd513a0dd1eb23c6 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 6 Mar 2025 17:33:56 +0100 Subject: [PATCH] Add filter for task 3 --- .python-version | 1 + pyproject.toml | 7 ++++ src/ImageFiltering.py | 90 +++++++++++++++++++++++++++++++++++-------- src/controllers.py | 16 +++++++- uv.lock | 8 ++++ 5 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 .python-version create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..2c07333 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4d3f6f0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "digba" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [] diff --git a/src/ImageFiltering.py b/src/ImageFiltering.py index ff051ee..f8984e2 100644 --- a/src/ImageFiltering.py +++ b/src/ImageFiltering.py @@ -45,12 +45,21 @@ def applyMedianFilter(img: ndarray, kSize: int): # create a moving average kernel of arbitrary size def createMovingAverageKernel(kSize): kernel = np.zeros((kSize, kSize)) + + f = 1.0/(kSize * kSize) + + for x in range(kSize): + for y in range(kSize): + kernel[x][y] = f + return kernel +# Won't use below cuz it would e muuuuch slooooower. def gaussian(x, y, sigmaX, sigmaY, meanX, meanY): - result = 1 - return result + px = (x-meanX)*(x-meanX)/(sigmaX*sigmaX) + py = (y-meanY)*(y-meanY)/(sigmaY*sigmaY) + return math.exp(-0.5 * ( px + py ))/(2*math.pi*sigmaX*sigmaY) # create a gaussian kernel of arbitrary size @@ -64,14 +73,12 @@ def createGaussianKernel(kSize, sigma=None): sum = 0.0 for x in range(kSize): - xm = x - kSize/2 - xsum = xm * xm / stdev2 + xm = x - math.floor(kSize/2) for y in range(kSize): - ym = y - kSize/2 - ysum = ym * ym / stdev2 + ym = y - math.floor(kSize/2) - kernel[x][y] = math.exp((xsum + ysum) * -0.5) * factor + kernel[x][y] = math.exp((xm*xm + ym*ym) / stdev2 * -0.5) * factor sum += kernel[x][y] # Normalize gaussian kernel in order not minimize power loss: @@ -85,14 +92,19 @@ def createGaussianKernel(kSize, sigma=None): # create a sobel kernel in x direction of size 3x3 def createSobelXKernel(): - kernel = np.zeros((3, 3)) - return kernel + + return np.array([ + [1, 0, -1], + [2, 0, -2], + [1, 0, -1]]) # create a sobel kernel in y direction of size 3x3 def createSobelYKernel(): - kernel = np.zeros((3, 3)) - return kernel + return np.array([ + [-1, -2, -1], + [0, 0, 0], + [1, 2, 1]]) def applyKernelInSpatialDomain(img, kernel): @@ -111,34 +123,82 @@ def applyKernelInSpatialDomain(img, kernel): for v in range(0, height): t = y + v - int(height/2) - color = np.zeros([3]) - if t >= 0 and t < img.shape[1] and s >= 0 and s < img.shape[0]: - color = img[s][t] + s = max(min(s, img.shape[0] - 1), 0) + t = max(min(t, img.shape[1] - 1), 0) + + color = img[s][t] filtered_img[x][y][0] += kernel[u][v] * color[0] filtered_img[x][y][1] += kernel[u][v] * color[1] filtered_img[x][y][2] += kernel[u][v] * color[2] + # Only for sobel, implemented in controller.py as workaround. + # filtered_img[x][y][0] = filtered_img[x][y][0] + 127 + # filtered_img[x][y][1] = filtered_img[x][y][1] + 127 + # filtered_img[x][y][2] = filtered_img[x][y][2] + 127 + return filtered_img # Extra: create an integral image of the given image def createIntegralImage(img): integral_image = img.copy() + + for x in range(0, img.shape[0]): + for y in range(0, img.shape[1]): + for c in range(3): + integral_image[x][y][c] = img[x][y][c] - img[x-1][y-1][c] + img[x+1][y][c] + img[x][y+1][c] + return integral_image # Extra: apply the moving average filter by using an integral image def applyMovingAverageFilterWithIntegralImage(img, kSize): filtered_img = img.copy() + integral_img = createIntegralImage(img) + + + return filtered_img # Extra: def applyMovingAverageFilterWithSeperatedKernels(img, kSize): filtered_img = img.copy() - return filtered_img + f = 1.0/(kSize) + + kernel = np.zeros((kSize, 1)) + for i in range(kSize): + kernel[i] = f + + for x in range(img.shape[0]): + for y in range(img.shape[1]): + for u in range(0, kSize): + s = x + u - int(kSize/2) + + s = max(min(s, img.shape[0] - 1), 0) + + color = img[s][y] + + filtered_img[x][y][0] += kernel[u] * color[0] + filtered_img[x][y][1] += kernel[u] * color[1] + filtered_img[x][y][2] += kernel[u] * color[2] + + for x in range(img.shape[0]): + for y in range(img.shape[1]): + for v in range(0, kSize): + t = y + v - int(kSize/2) + + t = max(min(t, img.shape[1] - 1), 0) + + color = img[t][y] + + filtered_img[x][y][0] += kernel[v] * color[0] + filtered_img[x][y][1] += kernel[v] * color[1] + filtered_img[x][y][2] += kernel[v] * color[2] + + return filtered_img def run_runtime_evaluation(img): pass diff --git a/src/controllers.py b/src/controllers.py index 969817d..f8bb863 100755 --- a/src/controllers.py +++ b/src/controllers.py @@ -134,15 +134,27 @@ class MainController: img = IF.applyMedianFilter(self._model.input_image, kernel_size) self._model.image = img + def apply_filter_sobelX(self): kernel = IF.createSobelXKernel() img = IF.applyKernelInSpatialDomain(self._model.input_image, kernel) - self._model.image = img + self._model.image = normalizeSobel(img) def apply_filter_sobelY(self): kernel = IF.createSobelYKernel() img = IF.applyKernelInSpatialDomain(self._model.input_image, kernel) - self._model.image = img + self._model.image = normalizeSobel(img) def run_runtime_evaluation(self): IF.run_runtime_evaluation(self._model.input_image) + +def normalizeSobel(img): + filtered_img = img.copy() + + for x in range(0, img.shape[0]): + for y in range(0, img.shape[1]): + filtered_img[x][y][0] = img[x][y][0] + 127 + filtered_img[x][y][1] = img[x][y][1] + 127 + filtered_img[x][y][2] = img[x][y][2] + 127 + + return filtered_img diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..0c22d14 --- /dev/null +++ b/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 1 +requires-python = ">=3.11" + +[[package]] +name = "digba" +version = "0.1.0" +source = { virtual = "." }