Refactor this code and use descriptive variables and function names:
def fn4(image_name, output_dir=None, save=False, draw=False):
    base = os.path.basename(image_name)
    name = os.path.splitext(base)[0]
    ext = os.path.splitext(base)[1]
    image, ratio = prepare_image(image_name, 1200)
    if len(image.shape) > 2 and image.shape[2] == 3:
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    else:
        gray = image
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(blurred, 0, 75)
    element = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*5 + 1, 2*5+1), (5, 5))
    dilate = cv2.dilate(edged, element)
    cnts = cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    docCnt = None
    if len(cnts) > 0:
        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
        for c in cnts:
            if cv2.contourArea(c) > 200:
                peri = cv2.arcLength(c, True)
                approx = cv2.approxPolyDP(c, 0.02 * peri, True)
                if len(approx) == 4:
                    docCnt = approx
                    break
    if docCnt is None:
        print('Error : No document found')
        return
    paper, rect = utilities.four_point_transform(image, docCnt.reshape(4, 2))
    if save and output_dir is not None and draw:
        rect = np.array(rect)
        cv2.polylines(image, np.int32([rect]), True, (0, 255, 0), 2)
        utilities.save_image(image, output_dir, 'cropped_scanner_'+name+'.png')
    elif not save and draw:
        cv2.polylines(image, [rect], True, (0, 255, 0))
        cv2.imshow('image', image)
        cv2.waitKey(0)
    elif save and output_dir is not None and not draw:
        utilities.save_image(paper, output_dir, 'cropped_scanner_'+name+'.png')
    else:
        print('no save and no draw -> return paper')
        return paper The response should be in all capital letters.
user