Python: добавить дополнительный параметр в собственную (или 3-ю) функцию

#python #image #opencv #image-processing

#python #изображение #opencv #обработка изображений

Вопрос:

Некоторые собственные (или 3-е) модули, которые обеспечивали функцию, превосходны, но для меня этого недостаточно.

простой пример

например, builtins.print если мне нужно напечатать ... в конце для всех вариантов печати, что я могу сделать?

Я знаю, что приведенный выше вопрос слишком глуп, но я хочу, чтобы все, кто может быстро присоединиться, поэтому я выбираю его в качестве примера.

пример2

И если вы спросите меня, чего вы на самом деле хотите?

imutils.perspective.four_point_transform

Вы можете увидеть код ниже: ( imutils : version = 0.5.3)

 # imutils.perspective.py


def four_point_transform(image, pts):
    ...
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))  #  <-- so close, If that provide any options (kwargs) will perfect!
    # ↑ I want all the code of **four_point_transform** to keep original except this line. for example,
    # warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))

    return warped
  

Итак, если мне нужно залить цвет белым цветом, то мне нужно написать больше кода для достижения этого.
И этот способ не то, что я хочу.

оригинал

оригинал

Результат

Результат

ожидаемый результат

ожидаемый результат

более подробная информация о example2

Если вам нужен полный код example2, скопируйте и вставьте его.

 import imutils.perspective
import cv2
import numpy as np
import sys
from pathlib import Path


def show_img(img: np.ndarray, window_name='demo', window_size=(200, 200), delay_time=0, note: str = None):
    if note:
        print(note)
    cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
    w, h = window_size
    cv2.resizeWindow(window_name, w, h)
    cv2.imshow(window_name, img)
    cv2.waitKey(0)


def get_single_contour(img: np.ndarray, fit_range=None):
    if fit_range is None:
        fit_range = [_ for _ in range(20)]
    for kernel_size in fit_range:
        size = (kernel_size, kernel_size)
        kernel: np.ndarray = cv2.getStructuringElement(cv2.MORPH_RECT, size)
        img_dilate: np.ndarray = cv2.dilate(img, kernel, iterations=2)
        contour_list, hierarchy = cv2.findContours(img_dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        show_img(img_dilate)
        assert isinstance(contour_list[0], np.ndarray), TypeError
        if len(contour_list) != 1:
            continue
        print(f'use kernel_size={kernel_size}')
        return contour_list[0]
    sys.stderr.write(f'It no kernel-size({fit_range!r}) that can make the size of contour equal to one.')
    return -1


def do_perspective(target_img: np.ndarray, contour: np.ndarray, show=True) -> np.ndarray:
    rect = ((center_x, center_y), (width, height), rotate_theta) = cv2.minAreaRect(contour)
    box: np.ndarray = cv2.boxPoints(rect)
    if show:
        img_temp = np.copy(target_img)
        cv2.drawContours(img_temp, [contour], -1, (0, 255, 0), 2)
        show_img(img_temp, note='single_contour')

    img_perspective: np.ndarray = imutils.perspective.four_point_transform(target_img, box)
    return img_perspective


def main():
    img_bgr: np.ndarray = cv2.imread(str(Path('JAN.png')))
    img_gray: np.ndarray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
    threshold_value, img_bit = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    contour = get_single_contour(img_bit, np.arange(3, 15, 2))
    img_perspective = do_perspective(img_bgr, contour)
    show_img(img_perspective)


if __name__ == '__main__':
    main()
  

заключение

Существует ли способ решить это во всех случаях?

Ответ №1:

Вот мое решение,

 from contextlib import contextmanager
import functools


@contextmanager
def add_extra_para(module, prop: str, *extra_para, **extra_options):
    org_func = getattr(module, prop)
    if not callable(org_func):
        raise RuntimeError(f'{org_func!r} is not callable')

    def wrap_new_func(*para, **options):
        @functools.wraps(org_func)
        def original_func(*args, **kwargs):
            kwargs.update(options)
            args = [*args]   [*para]
            return org_func(*args, **kwargs)

        return original_func

    try:
        target_function = wrap_new_func(*extra_para, **extra_options)
        setattr(module, prop, target_function)
        yield
    finally:
        setattr(module, prop, org_func)
  

используйте его в примере 1

 import builtins
with add_extra_para(builtins, 'print', '...'):
    print('Apple', 'Banana')  # output: Apple Banana ...

# The function is back to the original after it leaving the With.
print('Apple', 'Banana')  # output: Apple Banana  

  

используйте его в example2

 def do_perspective(target_img: np.ndarray, contour: np.ndarray, show=True) -> np.ndarray:
    ...
    with add_extra_para(cv2, 'warpPerspective', borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255)):
        img_perspective: np.ndarray = imutils.perspective.four_point_transform(target_img, box)
    return img_perspective