Warning: Can not open [/home/conf/public_html/cgi-bin/show_python.log]. Ignore cimg = img.copy()
if '_x' in ftype:
# filter[:, iy0] = cx
filter = np.zeros([ksize[0], 1])
filter[:, 0] = cx
cimg = cv2.filter2D(cimg, -1, filter)
if '_y' in ftype:
# filter[ix0, :] = cy
filter = np.zeros([1, ksize[1]])
filter[0, :] = cy
cimg = cv2.filter2D(cimg, -1, cy)

Download script from image_contrast.py
Related files:
image_contrast.gif


import sys
import numpy as np
from tqdm import tqdm, trange
from scipy.signal import savgol_coeffs
import cv2
import matplotlib.pyplot as plt


infile = 'stem.png'
outfile = 'normalized_image.png'
block_w = 20
block_h = 10
copy_w = 3
copy_h = 3

smooth_mode = 'poly' # 'gauss'
# for gauss and poly
smooth_w = 15
smooth_h = 15
# for poly
smooth_order = 3

view_w = 800


def usage():
    print()
    print(f"Usage: python {sys.argv[0]} infile block_w block_h copy_w copy_h view_w")

def initialize():
    global infile, outfile, block_w, block_h, copy_w, copy_h
    global smooth_mode, smooth_w, smooth_h, smooth_order
    global view_w

    infile = 'stem.png'
    outfile = 'normalized_image.png'
    block_w = 20
    block_h = 10
    copy_w = 3
    copy_h = 3
    smooth_mode = 'poly'
    smooth_w = 15
    smooth_h = 15
    smooth_order = 3

    view_w = 800


def update_vars():
    global infile, outfile, block_w, block_h, copy_w, copy_h
    global smooth_mode, smooth_w, smooth_h, smooth_order
    global view_w

    nargv = len(sys.argv)
    if nargv >= 2: infile = sys.argv[1]
    if nargv >= 3: block_w = int(sys.argv[2])
    if nargv >= 4: block_h = int(sys.argv[3])
    if nargv >= 5: copy_w = int(sys.argv[4])
    if nargv >= 6: copy_h = int(sys.argv[5])
    if nargv >= 7: smooth_mode = sys.argv[6]
    if nargv >= 8: smooth_w = int(sys.argv[7])
    if nargv >= 9: smooth_h = int(sys.argv[8])
    if nargv >= 10: smooth_order = int(sys.argv[9])
    if nargv >= 11: view_w = int(sys.argv[10])


def read_image(infile, color = cv2.IMREAD_GRAYSCALE):
    print()
    print(f"Read image [{infile}]")
    return cv2.imread(infile, color)

def save_image(img, outfile):
    print()
    print(f"Save converted image to [{outfile}]")
    cv2.imwrite(outfile, img)

def plot_image(img1, img2, img3, view_w = 600, mode = 'cv2'):
    print()
    print("plot")
    if len(img1.shape) == 2:
        height, width = img1.shape
    else:
        height, width, _ = img1.shape

    print(f"image shape: {width} x {height}")
    mag = view_w / width
    print(f"view width: {view_w} = {width} * {mag:.3f}")

    if img1 is not None:
        img1_resized = cv2.resize(img1, (int(width * mag + 1.0e-5), int(height * mag + 1.0e-5)), interpolation=cv2.INTER_LINEAR)
    if img2 is not None:
        img2_resized = cv2.resize(img2, (int(width * mag + 1.0e-5), int(height * mag + 1.0e-5)), interpolation=cv2.INTER_LINEAR)
    if img3 is not None:
        img3_resized = cv2.resize(img3, (int(width * mag + 1.0e-5), int(height * mag + 1.0e-5)), interpolation=cv2.INTER_LINEAR)

    if mode == 'cv2':
        cv2.imshow('Original Image', img1_resized)
        cv2.imshow('Converted Image', img2_resized)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    else:
        plt.figure(figsize=(15, 5))
        if img1 is not None:
            plt.subplot(1, 3, 1)
            plt.title('Original Image')
            plt.imshow(cv2.cvtColor(img1_resized, cv2.COLOR_BGR2RGB))

        if img2 is not None:
            plt.subplot(1, 3, 2)
            plt.title('Smoothed Image')
            plt.imshow(cv2.cvtColor(img2_resized, cv2.COLOR_BGR2RGB))

        if img3 is not None:
            plt.subplot(1, 3, 3)
            plt.title('Converted Image')
            plt.imshow(cv2.cvtColor(img3_resized, cv2.COLOR_BGR2RGB))

        plt.pause(1.0e-5)
        input("\nPress ENTER to terminate>>\n")

def smoothing(img, ftype, ksize, sigmaX = -1, norder = 3):
    if 'gauss' in ftype:
        print("gaussian smoothing:")
        return cv2.GaussianBlur(img, ksize, sigmaX)
    elif ftype == 'fft':
        print("fft smoothing:")
        fted = np.fft.fft2(img)
        fted_shift = np.fft.fftshift(fted)

        rows, cols = img.shape
        cy, cx = rows // 2 , cols // 2
        ry, rx = ksize
        for iy in range(rows):
            for ix in range(cols):
#                r2 = ((ix - cx) / rx)**2 + ((iy - cy) / ry)**2
#                if r2 > 1.0:
                if iy < cy - ry or cy + ry < iy or ix < cx - rx or cx + rx < ix:
                    fted_shift[iy][ix] = 0.0
        fted_origin = np.fft.ifftshift(fted_shift)
        img_back = np.fft.ifft2(fted_origin)
        img_back = np.abs(img_back)
#        img_back = img_back / max(img_back.flatten()) * 255.0

        img_back8 = np.zeros([rows, cols], np.uint8)
        for iy in range(rows):
            for ix in range(cols):
                img_back8[iy][ix] = img_back[iy][ix].real

#        return img_back.astype(np.uint8)
        return img_back8
    else:
        print(f"{norder}-th order polynomial fit smoothing using {ksize[0]} x {ksize[1]} points:")
#        filter = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) / 9.0
        cx = savgol_coeffs(ksize[0], norder)
        cy = savgol_coeffs(ksize[1], norder)

        filter = np.zeros(ksize)
        ix0 = int(ksize[0] / 2) + 1
        iy0 = int(ksize[1] / 2) + 1
        filter[:, iy0] = cx / cx[ix0]
        filter[ix0, :] = cy / cy[iy0]
        tot = sum(sum(row) for row in filter)
        filter /= tot
        cimg = cv2.filter2D(img, -1, filter)

        '''
        cimg = img.copy()
        if '_x' in ftype:
#            filter[:, iy0] = cx
            filter = np.zeros([ksize[0], 1])
            filter[:, 0] = cx
            cimg = cv2.filter2D(cimg, -1, filter)
        if '_y' in ftype:
#            filter[ix0, :] = cy
            filter = np.zeros([1, ksize[1]])
            filter[0, :] = cy
            cimg = cv2.filter2D(cimg, -1, cy)
        '''


        return cimg

def normalize_image(img, block_w, block_h, copy_w = 3, copy_h = 3):
    hdx0 = int(block_w / 2)
    hdy0 = int(block_h / 2)
    hcx0 = int(copy_w / 2)
    hcy0 = int(copy_h / 2)

    img_normalized = img.copy()
    height, width = img.shape

    def get_range(i, imax, w0):
        if i == 0 or i == imax - 1: w = 1
        elif i < w0: w = i
        elif imax - 1 - w0 < i: w = imax - w0
        else: w = w0

        range0 = i - w
        range1 = i + w
        if range0 < 0: range0 = 0
        if imax <= range1: range1 = imax

        return w, range0, range1

    for yc in trange(0, height + 2 * hcy0, 2 * hcy0 + 1):
        hdy, norm_y0, norm_y1 = get_range(yc, height, hdy0)

        for xc in range(0, width + 2 * hcx0, 2 * hcx0 + 1):
            hdx, norm_x0, norm_x1 = get_range(xc, width, hdx0)
#            print(f"xc/{width}=", xc, hdx, norm_x0, norm_x1)

            copy_y0 = yc - hcy0
            copy_y1 = yc + hcy0
            copy_x0 = xc - hcx0
            copy_x1 = xc + hcx0
#            print("copy:", copy_x0, copy_x1)

            block = img[norm_y0:norm_y1 + 1, norm_x0:norm_x1 + 1]
            vmin = block.min()
            vmax = block.max()
#            print("vmin,vmax=", vmin, vmax)
            if vmin != vmax:
                img_normalized[copy_y0:copy_y1 + 1, copy_x0:copy_x1 + 1] \
                        = (img[copy_y0:copy_y1 + 1, copy_x0:copy_x1 + 1] - vmin) / (vmax - vmin) * 255.0

    return img_normalized


def main():
    global infile, outfile, block_w, block_h, copy_w, copy_h, view_w, smooth_w, smooth_h

    initialize()
    update_vars()

    img = read_image(infile)
    height, width = img.shape
    print("image shape:", height, width)
    print("color range:", img.min(), img.max())

    print("block size:")
    print(" normalize:", block_w, block_h)
    if copy_w > block_w: copy_w = block_w
    if copy_h > block_h: copy_h = block_h
    print(" copy :", copy_w, copy_h)
    smooth_w = 2 * int(smooth_w / 2) + 1
    smooth_h = 2 * int(smooth_h / 2) + 1
    print(f"smoothing block ({smooth_mode}): {smooth_w} x {smooth_h}")

    img_smoothed = smoothing(img, smooth_mode, (smooth_w, smooth_h), -1, smooth_order)
    img_normalized = normalize_image(img_smoothed, block_w, block_h)

    save_image(img_normalized, outfile)

    plot_image(img, img_smoothed, img_normalized, view_w, mode = 'matplotlib')
#    plot_image(img, ftr, fti, mode = 'matplotlib')

    usage()


if __name__ == '__main__':
    main()