vieyahn2017 / pypy

python trial collections
1 stars 1 forks source link

Opencv2的图片监控 #14

Open vieyahn2017 opened 1 year ago

vieyahn2017 commented 1 year ago

Halcon那样的可视化工具 (matlab也有?)

visual studio的插件 Image Watch

https://blog.csdn.net/qq_39531155/article/details/113698915

pip install visual-logging pip install opencv-log

vieyahn2017 commented 1 year ago

pip install traceback-with-variables

vieyahn2017 commented 1 year ago

yh_cv2_log.py


import sys
import cvlog
import numpy as np

# from traceback_with_variables import activate_by_import

cvlog.set_mode(cvlog.Mode.LOG) # log_image
# cvlog.set_mode(cvlog.Mode.DEBUG) # show_image
cvlog.set_level(cvlog.Level.TRACE)

# test
def get_vars(frame_no=1):
    frame = sys._getframe(frame_no)
    print(frame.f_globals.items())
    print(frame.f_locals.items())

# 初步完成我的需求
# todo:动态变量监控,比如img一直在被重新赋值,动态记录
# todo:pyQt5做界面那种,Halcaon那种
def check_image_and_log(frame_no=1, mark_image=None, lineno=0):

    def _check_is_image(items, _shape=None):
        """ _shape传None的时候,取第一个符合要求的 """
        if _shape is None:
            for k, v in items:
                if type(v) == np.ndarray:
                    if len(v.shape) == 3 and v.shape[2] == 3:
                        check_shape = v.shape
        else:
            check_shape = _shape

        try:
            _rows, _cols = check_shape[:2]
        except:
            print("shape is invalid, maybe image is not existed.")
            return

        for k, v in items:
            # print(k)
            # print(type(v))
            if type(v) == np.ndarray:
                if len(v.shape) not in [2, 3]:
                    continue
                if len(v.shape) == 3 and v.shape[2] != 3:
                    continue
                # 对 _rows, _cols的匹配,目前看貌似没必要
                print("Line[{}]: {} is matched, shape is {}".format(lineno, k, v.shape))
                cvlog.image(cvlog.Level.INFO, v, msg="{} at {}".format(k, lineno))

    shape = None
    if mark_image is not None:
        shape = mark_image.shape

    frame = sys._getframe(frame_no)
    func = frame.f_code.co_name
    lineno = frame.f_lineno

    # print(frame.f_globals.keys())
    print(list(filter(lambda x: not x.startswith("__"), frame.f_globals.keys())))
    _check_is_image(frame.f_globals.items(), shape)

    if func != "<module>":
        # print(frame.f_locals.items())
        print(list(filter(lambda x: not x.startswith("__"), frame.f_locals.keys())))
        _check_is_image(frame.f_locals.items(), shape)
vieyahn2017 commented 1 year ago

最新:

import sys
import cvlog
import numpy as np

# from traceback_with_variables import activate_by_import

cvlog.set_mode(cvlog.Mode.LOG) # log_image
# cvlog.set_mode(cvlog.Mode.DEBUG) # show_image
cvlog.set_level(cvlog.Level.TRACE)

GLOBAL_HASH_DICT = dict()

# 1. 初步完成我的需求
# 2. images限定。已完成。测试语句 check_image_and_log(images=["image", "mask", "not_existed"])
# 3. 全局变量在当前函数没有改变,不做记录 【新加入GLOBAL_HASH_DICT,基本实现】
# todo:动态变量监控,比如img一直在被重新赋值,动态记录 【暂时没思路】(使用上规避了,单个上下文内,不要做变量覆盖写)
# 5. 优化cvlog的结果显示html_template 【基本完成】
# todo:pyQt5做界面那种,Halcaon那种
def check_image_and_log(frame_no=1, base_image=None, images=[]):

    frame = sys._getframe(frame_no)
    func = frame.f_code.co_name
    lineno = frame.f_lineno
    print(("GLOBAL_HASH_DICT:"), GLOBAL_HASH_DICT.items())

    if len(images) > 1:
        frame = sys._getframe(frame_no)
        func = frame.f_code.co_name
        lineno = frame.f_lineno

        f_globals = list(filter(lambda x: not x.startswith("__"), frame.f_globals.keys()))
        f_locals = list(filter(lambda x: not x.startswith("__"), frame.f_locals.keys()))

        for imgk in images:
            if imgk in f_locals:
                v = frame.f_locals[imgk]
                cvlog.image(cvlog.Level.INFO, v, msg="[local] {} at line {}".format(imgk, lineno))
                continue
            if imgk in f_globals:
                v = frame.f_globals[imgk]
                # vhash = hash(v) # TypeError: unhashable type: 'numpy.ndarray'
                vhash = hash(str(v))
                if imgk in GLOBAL_HASH_DICT.keys():
                    if vhash == GLOBAL_HASH_DICT[imgk]:
                        print("{} is existed, hash={}, skipped".format(imgk, vhash))
                        continue
                    else:
                        print("{} is existed, old hash={}, new hash={}".format(imgk, GLOBAL_HASH_DICT[imgk], vhash))
                GLOBAL_HASH_DICT[imgk] = vhash
                cvlog.image(cvlog.Level.INFO, v, msg="[global] {} at line {}".format(imgk, lineno))
                continue
            # print(imgk + " not found") # 防止手动传一个不存在的值

        return

    def _check_is_image(items, tip="local", shape=None):
        """ _shape传None的时候,取第一个符合要求的 """
        if shape is None:
            for k, v in items:
                if type(v) == np.ndarray:
                    if len(v.shape) == 3 and v.shape[2] == 3:
                        check_shape = v.shape
                        print(("shape:", check_shape))
                        break
        else:
            check_shape = shape

        try:
            _rows, _cols = check_shape[:2]
        except:
            print("shape is invalid, maybe image is not existed.")
            return

        for k, v in items:
            # print(k)
            # print(type(v))
            if type(v) == np.ndarray:
                if len(v.shape) not in [2, 3]:
                    continue
                if len(v.shape) == 3 and v.shape[2] != 3:
                    continue
                # 对 _rows, _cols 的匹配,完全匹配貌似没必要
                if v.shape[0] < _rows / 10:
                    continue
                if v.shape[1] < _cols / 10:
                    continue
                if tip == "global":
                    vhash = hash(str(v))
                    if k in GLOBAL_HASH_DICT.keys():
                        if vhash == GLOBAL_HASH_DICT[k]:
                            print("{} is existed, hash={}, skipped".format(k, vhash))
                            continue
                        else:
                            print("{} is existed, old hash={}, new hash={}".format(k, GLOBAL_HASH_DICT[k], vhash))
                    GLOBAL_HASH_DICT[k] = vhash

                print("Line[{}]: [{}] {} is matched, shape is {}".format(tip, lineno, k, v.shape))
                cvlog.image(cvlog.Level.INFO, v, msg="[{}] {} at line {}".format(tip, k, lineno))

    shape = None
    if base_image is not None:
        shape = base_image.shape

    # print(frame.f_globals.keys())
    print(list(filter(lambda x: not x.startswith("__"), frame.f_globals.keys())))
    _check_is_image(frame.f_globals.items(), shape=shape, tip="global")

    if func != "<module>":
        # print(frame.f_locals.items())
        print(list(filter(lambda x: not x.startswith("__"), frame.f_locals.keys())))
        _check_is_image(frame.f_locals.items(), shape=shape, tip="local")

###################  分界线 ###################

# test
def get_vars(frame_no=1):
    frame = sys._getframe(frame_no)
    print(frame.f_globals.items())
    print(frame.f_locals.items())

# test wrapper
def show_caller(level=1):
    def show(func):
        def wrapper(*args, **kwargs):
            func(*args, **kwargs)
            print('{0.f_code.co_filename}:{0.f_lineno}'.format(sys._getframe(level)), "->", func.__name__)

        return wrapper

    return show

@show_caller(1)
def foo(): pass

# foo()

def yh_cv2_logger0(func):  # 包两层,参数为func,不能传入自己的参数
    # def mylog(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)  # 希望的是在func这里面的frame执行我的check_image_and_log()
        check_image_and_log()           # 但是实际上变成顺序执行,压根不在同一个栈帧
        # check_image_and_log(frame_no=frame_no, base_image=base_image, images=images)
        return result
    return wrapper
    # return mylog

# 装饰器的方式 # 包三层,最外层传递参数,第二层是接收func参数的装饰器
# 放弃了,sys._getframe 在装饰器里感觉有点无解,无法传递到符合预期的值
def yh_cv2_logger(frame_no=1, base_image=None, images=[]):
    def mylog(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            check_image_and_log(frame_no=frame_no, base_image=base_image, images=images)
            return result
        return wrapper
    return mylog

# https://blog.csdn.net/qq_39093583/article/details/126997392
class Hook:
    """
    hook 方法,实例化后,获取调用链路上一个函数名及参数信息,call后执行函数
    # 也想着按照这样的方式,在Hook里去调用check_image_and_log,但是栈帧始终不行,放弃。
    """

    def __init__(self, obj: object()):
        _ancestors = obj.__class__.mro()
        _f_back = sys._getframe().f_back

        self.cls_name = _f_back.f_code.co_name
        self.kwargs = _f_back.f_locals
        self.kwargs.pop('self')

        if len(_ancestors) > 2:  # 超过一层继承抛出异常
            raise EnvironmentError(f'method: {self.cls_name} unimplemented')

    def __call__(self, obj: object()):
        return getattr(obj, self.cls_name)(**self.kwargs)

class Base:
    def add(self, num):
        return Hook(self)

class A(Base):
    def __init__(self, result):
        self.result = result

    def add(self, num):
        return self.result + num

if __name__ == '__main__':
    b = Base()
    h = b.add(23)
    print(h.cls_name, h.kwargs)
    a = A(10)
    print(h(a))
vieyahn2017 commented 1 year ago

5. 优化cvlog的结果显示html_template 【基本完成】

以这个来的

css 实现多张图片响应式水平排列自适应效果

vieyahn2017 commented 1 year ago

cvlog\html_logger.py

修改了两个方法

    def log_image(self, level, log_type, img_data, msg):
        data = ''.join(['<img src="data:image/png;base64, ', img_data, '" style="max-width: 100%;"/>'])
        self.__append_log_item(level, log_type, data, msg)

    def __append_log_item(self, level, log_type, log_detail, msg):
        short_stack, data = self.__get_log_info()
        template = '<div class="quarter">'
        template += '<div>' + data['time_stamp'] + '</div>'
        if msg:
            # template += '<div><pre id="description">[global] SRC2 at line 33</pre></div>'
            template += '<div><pre">' + msg + '</pre></div>'
        # template += '<div id="ld_log_data"><img src="1.jpg" style="max-width: 100%;"/></div>'
        template += '<div>' + log_detail + '</div>'
        template += '<div><pre>' + re.sub(r'^/', '', short_stack) + '</pre></div>'
        template += '</div>'
        self.__try_append([template])

cvlog\html_template.py 全面修改了


CONTENT_START = '<body><div class="log-container"><div class="log-lists"> '
CONTENT_END = '</div></body></html>'
NO_DATA_CONTENT = '<div id="no-data">No data logged</div>'
SCRIPT = '<script>/* No need */ </script>'
STYLE = '<style>body{width: 100%; height: 100%; margin: 0px; font-family:Arial, Helvetica, sans-serif;} .quarter{float: left;width: 25%;box-sizing: border-box;padding: 10px;min-width: 150px;} @media (max-width:615px ) {.quarter{float: left;width: 33%;box-sizing: border-box;padding: 10px;min-width: 150px;}} @media (max-width:465px ) {.quarter{float: left;width: 50%;box-sizing: border-box;padding: 10px;min-width: 150px;}} @media (max-width:315px ) {.quarter{float: left;width: 100%;box-sizing: border-box;padding: 10px;}}</style>'