Django
Django Image Processing Webapp Part III

Django Image Processing Webapp Part III

In third part, we will process the image according to the options selected by the user.

Table of Contents

Basic filters

Main Module

We will create separate file Image/basic.py to handle all the functions related to basic filters.

#Install numpy
pip install numpy


from django.core.files import File

import numpy as np
from PIL import Image
from PIL import ImageFilter
from io import BytesIO


def Bit_Plane(input_image,bit=7):

    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))
    
    numpy_image = np.array(img)
    #Iterate over each pixel and change pixel value to binary using np.binary_repr() and store it in a list.
    lst = []
    for i in range(numpy_image.shape[0]):
        for j in range(numpy_image.shape[1]):
            lst.append(np.binary_repr(numpy_image[i][j] ,width=8)) # width = no. of bits

    value = (pow(2,(bit-1)))
    
    # We have a list of strings where each string represents binary pixel value. To extract bit planes we need to iterate over the strings and store the characters corresponding to bit planes into lists.
    # # Multiply with 2^(n-1) and reshape to reconstruct the bit image.
    eight_bit_img = (np.array([int(i[0]) for i in lst],dtype = np.uint8) * value).reshape(400,400)
    bit_sliced_image = Image.fromarray(eight_bit_img)

    final_image = bit_sliced_image .convert("L")

    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]



def Log_transform(input_image):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    #img = input_image.resize((400,400), Image.ANTIALIAS)
    numpy_image = np.array(img)
    numpy_image = np.array(img)
    numpy_image = numpy_image/255
    numpy_image = numpy_image + 1
    numpy_image = np.log(numpy_image)
    print(type(numpy_image))
    numpy_image = numpy_image * 255
    numpy_image = np.around(numpy_image,decimals=0)
    log_image = Image.fromarray(numpy_image)
    log_image = log_image.convert("L")

    out_io = BytesIO()
    log_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)



    return [img,out_final]


def Power_transform(input_image,gamma=2):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    numpy_image = np.array(img)
    numpy_image = numpy_image/255
    numpy_image_a = np.power(numpy_image,gamma)
    numpy_image_a = numpy_image_a * 255
    numpy_image_a = np.around(numpy_image_a,decimals=0)
    power_image = Image.fromarray(numpy_image_a)
    power_image = power_image.convert("L")


    out_io = BytesIO()
    power_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)
   

    return [img,out_final]

def Threshold(input_image,threshold=150):
    
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    numpy_image = np.array(img)
    
    row = numpy_image.shape[0]
    column = numpy_image.shape[1]
    new_array = np.zeros(shape=(row,column))

    for i in range(row):
        for j in range(column):
            if(numpy_image[i][j]>=threshold):
                new_array[i][j] = 255 
            else:
                new_array[i][j] = 0
            
    #converting array back to image
    threshold_image = Image.fromarray(new_array)  
    threshold_image = threshold_image.convert("L")


    out_io = BytesIO()
    threshold_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)
    

    return [img,out_final]


def Negative(input_image):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    numpy_image = np.array(img)

    row = numpy_image.shape[0]
    column = numpy_image.shape[1]
    new_array = np.zeros(shape=(row,column))
    for i in range(row):
        for j in range(column):
            new_array[i][j] = 255 - numpy_image[i][j]
    
    negative_image = Image.fromarray(new_array)
    
    negative_image = negative_image.convert("L")
    
    
    out_io = BytesIO()
    negative_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)
    

    return [img,out_final]

def Histogram_equalization(input_image):
    img_main = Image.open(input_image).convert('L')
    img_main = img_main.resize((400,400))


    # # convert our image into a numpy array
    img = np.asarray(img_main)
    # put pixels in a 1D array by flattening out img array
    flat = img.flatten()

    # show the histogram
    #plt.hist(flat, bins=256)

    histogram = np.zeros(256)
    # loop through pixels and sum up counts of pixels
    for pixel in flat:
        histogram[pixel] += 1

    #plt.plot(histogram)

    a = iter(histogram)
    b = [next(a)]
    for i in a:
        b.append(b[-1] + i)

    cs = np.array(b)

    # numerator & denomenator
    nj = (cs - cs.min()) * 255
    N = cs.max() - cs.min()

    # re-normalize the cumsum
    cs = nj / N

    # cast it back to uint8 since we can't use floating point values in images
    cs = cs.astype('uint8')


    # get the value from cumulative sum for every index in flat, and set that as img_new
    img_new = cs[flat]
  

    # put array back into original shape since we flattened it
    img_new = np.reshape(img_new, img.shape)


    histo_image = Image.fromarray(img_new)
    
    histo_image = histo_image.convert("L")


    out_io = BytesIO()
    histo_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img_main.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)
    

    return [img,out_final]

Adding method for bit plane slicing in model

To handle the request for filters in our model, edit Image/models.py file.

..........................................
from . import basic
...........................

# Create your models here.
class ImageEnhance(models.Model):
    title = models.CharField(max_length=50)
    image = models.ImageField(upload_to="",blank=True,null=True)
    image_enhanced = models.ImageField(upload_to="",blank=True,null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)
    
    def rotateMe(self,deg=90,*args,**kwargs):
        self.image_enhanced = imageRotate(self.image,deg)
        super().save(*args,**kwargs)

    def transposeMe(self,*args,**kwargs):
        self.image_enhanced = imageTranspose(self.image)
        super().save(*args,**kwargs)

    #Handling basic operations
    def bitPlane(self,bit=3,*args,**kwargs):#new
        #new
        self.image,self.image_enhanced = basic.Bit_Plane(self.image,bit)
        super().save(*args,**kwargs)#new

    def __str__(self):
        return self.title

In above code, we added method for bit plane slicing.

Bit Plane view

We need to edit Image/views.py to read and respond the request of bitPlane slicing.

..................................................
def imageForm(request):
    if request.method == 'POST':
        form = ImageForm(request.POST,request.FILES)
        if form.is_valid():
            #save the model instance
            instance = form.save(commit=False)
            
            instance.save()

            return render(request,"image_process.html",{"form":form,'object':instance})
        else:
            latest_object = ImageEnhance.objects.latest('id')
            process = request.POST["first-dropdown"]
            try:
                sub_process = request.POST["second-dropdown"]
                tuning_value = request.POST["num-Input"]
            except:
                pass

            if process == '1':
                print("************Basic Selected")
                print(sub_process)

                if sub_process == '1B':
                    print("********* Bit Plane Slicing Selected")
                    tuning_value = int(tuning_value)
                    latest_object.bitPlane(tuning_value)

                    return render(request,"image_process.html",{"form":form,"object":latest_object})
                return HttpResponse("Basic Selected")
            ...........................................

The result of Bit Plane Slicing

Adding methods for rest of the basic image processing function


......................................................................
# Create your models here.
class ImageEnhance(models.Model):
    title = models.CharField(max_length=50)
    image = models.ImageField(upload_to="",blank=True,null=True)
    image_enhanced = models.ImageField(upload_to="",blank=True,null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)
    
    def rotateMe(self,deg=90,*args,**kwargs):
        self.image_enhanced = imageRotate(self.image,deg)
        super().save(*args,**kwargs)

    def transposeMe(self,*args,**kwargs):
        self.image_enhanced = imageTranspose(self.image)
        super().save(*args,**kwargs)

    #Handling basic operations
    def bitPlane(self,bit=3,*args,**kwargs):
        
        self.image,self.image_enhanced = basic.Bit_Plane(self.image,bit)
        super().save(*args,**kwargs)


    def powerTransform(self,gamma=2,*args,**kwargs):
        self.image,self.image_enhanced = basic.Power_transform(self.image,gamma)
        super().save(*args,**kwargs)

    def thresholdImage(self,threshold=150,*args,**kwargs):
        self.image,self.image_enhanced = basic.Threshold(self.image,threshold)
        super().save(*args,**kwargs)

    def negativeImage(self,*args,**kwargs):
        self.image,self.image_enhanced = basic.Negative(self.image)
        super().save(*args,**kwargs)

    def histogramEqImage(self,*args,**kwargs):
        self.image,self.image_enhanced = basic.Histogram_equalization(self.image)
        super().save(*args,**kwargs)


    def __str__(self):
        return self.title

Receiving and responding to request in Image/views.py


........................................................
if process == '1':
                print("************Basic Selected")
                print(sub_process)

                if sub_process == '1B':
                    print("********* Bit Plane Slicing Selected")
                    tuning_value = int(tuning_value)
                    latest_object.bitPlane(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object})
                
                elif sub_process == "1C":
                    print("********* Power Transform Selected")
                    tuning_value = float(tuning_value)
                    latest_object.powerTransform(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object})
                elif sub_process == "1D":
                    print("******************* Image Threshold selected")
                    tuning_value = float(tuning_value)
                    latest_object.thresholdImage(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object})
                
                elif sub_process == "1E":
                    print("******************* Negative Image selected")
                    latest_object.negativeImage()
                    return render(request,"image_process.html",{"form":form,"object":latest_object})
                
                elif sub_process == "1F":
                    print("******************* Histogram Equalization selected")
                    latest_object.histogramEqImage()
                    return render(request,"image_process.html",{"form":form,"object":latest_object})



                
                return render(request,"image_process.html",{"form":form,"object":latest_object})
            
................................................................

The Power Transform Output

Thresholding the same image at 56

Generating the negative

Result of Histogram Equalization

Spatial filters

Module

Add Image/spatial.py file and fill it with following code.

from django.core.files import File

import numpy as np
from PIL import Image
from PIL import ImageFilter
from io import BytesIO

def Smooth_Filter(input_image,kernel_size = 3):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    # convert to numpy array 
    numpy_image = np.array(img)

    #array for padding
      #array for padding
    x = 400+(kernel_size-1)
    y = 400+(kernel_size-1)
    array_b = np.zeros((x,y))
    

    #to pad initial array with zeros
    array_b[1:401,1:401] = numpy_image

    #defining filter
     #defining filter
    filter_array = np.full((kernel_size, kernel_size), 1/9)

    #creating an empty list
    lst = []
    for i in range(400):
        for j in range(400):
            #extracting part of array equal to filter size
            array_c = array_b[i:(kernel_size+i),j:(kernel_size+j)]
            
            #applying filter
            array_mul = np.multiply(filter_array,array_c)
            array_sum = np.sum(array_mul)
            
            # putting calculated value in list
            lst.append(array_sum)

    #resizing lst to shape of original array
    final_array = np.resize(lst,(400,400))

    final_image = Image.fromarray(final_array)
    final_image = final_image.convert("L")


    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]
  

def Sharp_Filter(input_image,kernel_size=3):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    # convert to numpy array 
    numpy_image = np.array(img)

    #array for padding
    x = 400+(kernel_size-1)
    y = 400+(kernel_size-1)
    array_b = np.zeros((x,y))
    

    #to pad initial array with zeros
    array_b[1:401,1:401] = numpy_image

    denominator = (kernel_size*kernel_size)
    filter_array = np.full((kernel_size, kernel_size), -1/denominator)
    center = int((kernel_size-1)/2)
    filter_array[center,center] = (denominator-1)/denominator
   


    #creating an empty list
    lst = []
    for i in range(400):
        for j in range(400):
            #extracting part of array equal to filter size
            array_c = array_b[i:(kernel_size+i),j:(kernel_size+j)]
            
            #applying filter
            array_mul = np.multiply(filter_array,array_c)
            array_sum = np.sum(array_mul)
            
            # putting calculated value in list
            lst.append(array_sum)

    #resizing lst to shape of original array
    final_array = np.resize(lst,(400,400))

    final_image = Image.fromarray(final_array)
    final_image = final_image.convert("L")

    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final,final_image]



def Min_Filter(input_image,kernel_size=3):
    

    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))


    # convert to numpy array 
    numpy_image = np.array(img)

    #array for padding
    x = 400+(kernel_size-1)
    y = 400+(kernel_size-1)
    array_b = np.zeros((x,y))
    

    #to pad initial array with zeros
    array_b[1:401,1:401] = numpy_image

  

    #defining filter
    
    filter_array = np.full((kernel_size, kernel_size), kernel_size)

    #creating an empty list
    lst = []
    for i in range(400):
        for j in range(400):
            #extracting part of array equal to filter size
            array_c = array_b[i:(kernel_size+i),j:(kernel_size+j)]
            
            #applying filter
            array_mul = np.multiply(filter_array,array_c)
            array_sum = np.min(array_mul)
            
            # putting calculated value in list
            lst.append(array_sum)

    #resizing lst to shape of original array
    final_array = np.resize(lst,(400,400))

    final_image = Image.fromarray(final_array)
    final_image = final_image.convert("L")


    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]


def Max_Filter(input_image,kernel_size=3):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))
    # convert to numpy array 
    numpy_image = np.array(img)

    #array for padding
    #array for padding
    x = 400+(kernel_size-1)
    y = 400+(kernel_size-1)
    array_b = np.zeros((x,y))
    

    #to pad initial array with zeros
    array_b[1:401,1:401] = numpy_image

  

    #defining filter
    
    filter_array = np.full((kernel_size, kernel_size), kernel_size)

    #creating an empty list
    lst = []
    for i in range(400):
        for j in range(400):
            #extracting part of array equal to filter size
            array_c = array_b[i:(kernel_size+i),j:(kernel_size+j)]
            
            #applying filter
            array_mul = np.multiply(filter_array,array_c)
            array_sum = np.max(array_mul)
            
            # putting calculated value in list
            lst.append(array_sum)

    #resizing lst to shape of original array
    final_array = np.resize(lst,(400,400))

    final_image = Image.fromarray(final_array)
    final_image = final_image.convert("L")


    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]


def Median_Filter(input_image,kernel_size=3):
    

    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))
    # convert to numpy array 
    numpy_image = np.array(img)

    #array for padding
    x = 400+(kernel_size-1)
    y = 400+(kernel_size-1)
    array_b = np.zeros((x,y))
    

    #to pad initial array with zeros
    array_b[1:401,1:401] = numpy_image

  

    #defining filter
    
    filter_array = np.full((kernel_size, kernel_size), kernel_size)

    #creating an empty list
    lst = []
    for i in range(400):
        for j in range(400):
            #extracting part of array equal to filter size
            array_c = array_b[i:(kernel_size+i),j:(kernel_size+j)]
            
            #applying filter
            array_mul = np.multiply(filter_array,array_c)
            array_sum = np.median(array_mul)
            
            # putting calculated value in list
            lst.append(array_sum)

    #resizing lst to shape of original array
    final_array = np.resize(lst,(400,400))

    final_image = Image.fromarray(final_array)
    final_image = final_image.convert("L")


    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]



def High_Boost(input_image,kernel_size=3):
    high_pass = Sharp_Filter(input_image,kernel_size)
    high_pass = high_pass[2]

    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

   
    # convert to numpy array 
    numpy_image = np.array(img)

    A = 3
    high_boost = (A-1)*numpy_image + high_pass
    final_image = Image.fromarray(high_boost)
    final_image= final_image.convert("L")


    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]

Adding methods for spatial filters in models.py

......................
from . import spatial
........................
#methods for spatial filters
    def smoothFilter(self,kernel_size=3,*args,**kwargs):
    
        self.image,self.image_enhanced = spatial.Smooth_Filter(self.image,kernel_size)
        super().save(*args,**kwargs)

    def sharpFilter(self,kernel_size=3,*args,**kwargs):
        self.image,self.image_enhanced,_ = spatial.Sharp_Filter(self.image,kernel_size)
        super().save(*args,**kwargs)

    def minFilter(self,kernel_size=3,*args,**kwargs):
        self.image,self.image_enhanced = spatial.Min_Filter(self.image,kernel_size)
        super().save(*args,**kwargs)

    def maxFilter(self,kernel_size=3,*args,**kwargs):
        self.image,self.image_enhanced = spatial.Max_Filter(self.image,kernel_size)
        super().save(*args,**kwargs)

    def medianFilter(self,kernel_size=3,*args,**kwargs):
        self.image,self.image_enhanced = spatial.Median_Filter(self.image,kernel_size)
        super().save(*args,**kwargs)

    def highBoostFilter(self,kernel_size=3,*args,**kwargs):
        self.image,self.image_enhanced = spatial.High_Boost(self.image,kernel_size)
        super().save(*args,**kwargs)


    

Receiving and responding to request in Image/views.py

.......................................................
elif process == '2':
                print("************ Spatial Filter Selcted")
                print(sub_process)

                if sub_process == "2B":
                    print("************************Smooth filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.smoothFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Smooth filter"})
                
                elif sub_process == "2C":
                    print("************************ Sharp filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.sharpFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Sharp filter"})
                
                elif sub_process == '2D':
                    print("************************ Min filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.minFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Min filter"})
                
                elif sub_process == '2E':
                    print("************************ Max filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.maxFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Max filter"})
                
                elif sub_process == '2F':
                    print("************************ Median filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.medianFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Median filter"})
                
                elif sub_process == '2G':
                    print("************************ High boost filter selected")
                    tuning_value = int(tuning_value)
                    latest_object.highBoostFilter(tuning_value)
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"High Boost"})
                
.............................................................

Result of Spatial Filter

Output of Smooth filter

Output of Sharp filter

Output of Min filter

Output of Max Filter

Output of Median Filter

Output of High Boost

Frequency Filters

The Module

Create Image/frequency.py

#terminal
pip install scipy
from django.core.files import File

import numpy as np
from PIL import Image,ImageDraw
from PIL import ImageFilter
from io import BytesIO
from scipy import fftpack


def low_pass_filter(input_image):
    
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))

    #convert image to numpy array
    image1_np=np.array(img)
    #fft of image
    fft1 = fftpack.fftshift(fftpack.fft2(image1_np))
    #Create a low pass filter image
    x,y = image1_np.shape[0],image1_np.shape[1]

    #defining filter
    #size of circle
    e_x,e_y=50,50
    #create a box 
    bbox=((x/2)-(e_x/2),(y/2)-(e_y/2),(x/2)+(e_x/2),(y/2)+(e_y/2))
    low_pass=Image.new("L",(image1_np.shape[0],image1_np.shape[1]),color=0)
    draw1=ImageDraw.Draw(low_pass)
    draw1.ellipse(bbox, fill=1)
    low_pass_np=np.array(low_pass)
    low_pass_np = low_pass_np.T
    #end of defining filter

    #multiply both the images
    filtered=np.multiply(fft1,low_pass_np)

    #inverse fft
    ifft2 = np.real(fftpack.ifft2(fftpack.ifftshift(filtered)))
    ifft2 = np.maximum(0, np.minimum(ifft2, 255))
    data = Image.fromarray(ifft2)  
    low_pass_array = data
    data = data.convert("L") 
    final_image = data

    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final,low_pass_array]
  

def high_pass_filter(input_image):
    img = Image.open(input_image).convert('L')
    img = img.resize((400,400))


    #converting image to array
    image_array = np.array(img)

    #sending image to low pass filter
    
    lowpass_image_array = low_pass_filter(input_image)[2]
    
   
    #subtracting lowpass image from original to obtain highpass image
    high_pass_array = image_array - lowpass_image_array
    print(high_pass_array.shape)

    #array to image
    high_pass_image = Image.fromarray(high_pass_array)  
    high_pass_image = high_pass_image.convert("L")

    final_image = high_pass_image

    out_io = BytesIO()
    final_image.save(out_io,'PNG',quality=85)
    out_final = File(out_io,name=input_image.name)

    in_io = BytesIO()
    img.save(in_io,'PNG',quality=85)
    img = File(in_io,name=input_image.name)

    return [img,out_final]

Created methods for frequency filters in models.py

................................................
    #Frequency filters
    def lowpassFilter(self,*args,**kwargs):
        self.image,self.image_enhanced,_ = frequency.low_pass_filter(self.image)
        super().save(*args,**kwargs)

    def highpassFilter(self,*args,**kwargs):
        self.image,self.image_enhanced = frequency.high_pass_filter(self.image)
        super().save(*args,**kwargs)
............................................

Handling response in views.py


..........................................................................
elif process == '3':
                print("************ Freuency Filter Selected")

                if sub_process == "3B":
                    print("*********************Low pass filter selected")
                    latest_object.lowpassFilter()
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"Low pass filter"})
                
                elif sub_process == "3C":
                    print("*********************High pass filter selected")
                    latest_object.highpassFilter()
                    return render(request,"image_process.html",{"form":form,"object":latest_object,"filter":"High pass filter"})

                return render(request,"image_process.html",{"form":form,"object":latest_object})
            
................................................................

Output of Frequency Filters

Output of low pass filter

Output of High Pass filter

Git push

#terminal
git add .
git commit -m "Modules of IP added"
git push

In part IV, we will add pagination to our home page.