예제 #1
0
def find_offset(fname_path, xy=None, meter_id=None, code=None):
    # if not fname_path.endswith('008_v.jpg'):
    #     return
    if xy is None:
        xy = (978, 516)
    xy = tuple(map(int, xy))

    image0 = cv.imread(fname_path)  # , cv.IMREAD_GRAYSCALE)
    # Debug.log_image('image0')
    qr_list = QrDecode.get_all_qrs(image0)
    if not len(qr_list):
        logger.error(f' not found any qr mark in {fname_path}')
        return 9999, 9999
    # if len(qr_list) > 1:
    # Debug.error(f' more than one ({len(qr_list)}) marks in {fname_path}')
    # qr_list = sorted(qr_list, key=lambda x: x.box.area(), reverse=True)
    qr_list = [qr_mark for qr_mark in qr_list if code == qr_mark.code.decode('utf-8')]
    if not len(qr_list):
        logger.error(f'not found mark for code {code} in file {fname_path}')
        return 9999, 9999
    anchor = qr_list[0].anchor

    img = image0.copy()
    cv.circle(img, xy, 10, colors.BGR_YELLOW, 2)
    KeyPoint.draw_list(anchor, ['kp', 'kp1', 'kp2'], img)
    Debug.log_image(f'{meter_id}_offs_target', img)

    offset = KeyPoint.xy_to_offset(xy, anchor)
    print(f'file {fname_path}:  code={qr_list[0].code} offset={offset[0]:.5f},{offset[1]:.5f}')
    return offset
예제 #2
0
def main_find_qr():
    shutil.rmtree(Cfg.log_folder, ignore_errors=True)
    os.makedirs(Cfg.log_folder, exist_ok=True)
    Debug.set_params(log_folder=Cfg.log_folder, log_image=Cfg.verbose)

    for folder in sorted(glob.glob(f'{Cfg.inp_folders}')):
        if not os.path.isdir(folder):
            continue

        files_cnt = 0
        files_found = 0
        for fname_path in glob.glob(f'{folder}/{Cfg.inp_fname_mask}'):
            Debug.set_log_image_names(fname_path)

            ok_cnt = process_file(fname_path)
            # ok_cnt=0
            # find_offset(fname_path)

            if ok_cnt:
                files_found += 1
            files_cnt += 1
            print(
                f'\t\t{fname_path}: {ok_cnt} marks.  Files: '
                f'{files_found}/{files_cnt} rate={100*files_found/files_cnt:.2f}%')

        print(f'Folder {folder}: {files_found}/{files_cnt} rate={100*files_found/files_cnt:.2f}%')
예제 #3
0
def main():
    shutil.rmtree(res_folder, ignore_errors=True)
    os.makedirs(res_folder, exist_ok=True)
    tot_cnt, ok_cnt = 0, 0

    for fname_path in glob.glob(f'{inp_folder}/{inp_mask}'):
        Debug.set_log_image_names(fname_path, res_folder)
        image0 = cv.imread(fname_path, cv.IMREAD_GRAYSCALE)

        qr_anchor_list = QrAnchorList(
            image0)  # qr_anchor - 3 big squares keypoints

        for qr_anchor in qr_anchor_list:

            qr_area = QrArea(
                image0, qr_anchor
            )  # qr_are is a part of image0 with qr_code and all related methods
            # qr_area_img = qr_area.draw()
            # Debug.log_image('qr_area_img')

            qr_list = qr_read.QrMarkList(qr_area.image_finished)
            qr_list.draw_boxes()
            qr_list.draw_polygons()

            found = len(qr_list.qr_marks)

            ok_cnt += 1 if found else 0
        tot_cnt += 1
        print(
            f'{fname_path}: Total: {ok_cnt}/{tot_cnt} ({ok_cnt/tot_cnt*100:.2f}%)'
        )
예제 #4
0
 def __init__(self, anchors):
     # anchors --> candidate_areas:
     self.image = anchors.image
     self.anchors = anchors.anchors
     self.candidate_qr_areas = []
     for ind in range(len(self.anchors)):
         anchor = self.anchors[ind]
         kp, kp1, kp2 = anchor
         # # if Cfg.area_preparing_method == 'warp_affine':  # todo remove, it's just a test
         # #     # Extract subregion of qr_area from the entire image
         # #     qr_area = self.get_subimage_warp(anchor, self.image)
         # #     Debug.log_image('area_after_warp', qr_area)
         # else:  # method=='subimage': find 4th corner -> stretch -> fit_to_shape -> crop
         # find 4th point
         kp4 = kp.find_4th_corner(kp1, kp2)  # 3 squares --> 4th square
         # rectangle of 4 square centers --> qr_area rectangle
         corners = KeyPoint.expand(kp1, kp, kp2, kp4, Cfg.expand_ratio)
         # correct corners which are out of image (after stretching)
         qr_area_keypoints = KeyPoint.fit_to_shape(corners, self.image.shape)
         # Extract subregion of qr_area from the entire image
         qr_area, center, size, theta = self.get_subimage(qr_area_keypoints, self.image)
         # make otsu binarization if ordered in Cfg
         if Cfg.use_otsu_threshold:
             blur = cv.GaussianBlur(qr_area, (5, 5), 0)
             ret, candidate_area = cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
         else:
             candidate_area = qr_area
         # set axis info (cross_x,cross_y,xaxis_angle)
         Debug.log_image(f'finished_{ind}', candidate_area)
         self.candidate_qr_areas.append((candidate_area, center, size, theta))
예제 #5
0
    def __init__(self, image, qr_ancor):
        self.image = image
        self.qr_anchor = qr_ancor
        self.center = KeyPoint(size=0,
                               x=int(mean([kp.x for kp in self.qr_anchor])),
                               y=int(mean([kp.x for kp in self.qr_anchor])))
        self.radius = max([self.center.distance(kp) for kp in qr_ancor])

        self.qr_roi = self.image[self.center.x - self.radius:self.center.x +
                                 self.radius, self.center.y -
                                 self.radius:self.center.y + self.radius]

        blur = cv.GaussianBlur(self.qr_roi, (5, 5), 0)
        ret, self.thresh_otsu = cv.threshold(blur, 0, 255,
                                             cv.THRESH_BINARY + cv.THRESH_OTSU)

        ret2, self.image_thresholded = cv.threshold(image, self.thresh_otsu,
                                                    255, cv.THRESH_BINARY)

        self.mask = np.zeros(self.image_thresholded.shape, dtype=np.uint8)
        self.mask[self.center.x - self.radius:self.center.x + self.radius,
                  self.center.y - self.radius:self.center.y +
                  self.radius] = 255
        Debug.log_image('mask')

        self.image_finished = self.image_thresholded
        self.image_thresholded[self.mask == 0] = 255
        Debug.log_image('image_finished')
예제 #6
0
 def draw_anchors(self):
     for ind in range(len(self.anchors)):
         anchor = self.anchors[ind]
         img = cv.cvtColor(self.image, cv.COLOR_GRAY2BGR)
         for kp in anchor:
             cv.circle(img, (kp.x, kp.y), kp.size, colors.BGR_RED, 2)
         anchor[0].draw_beam(anchor[1], ' ', img, colors.BGR_ORANGE)  # angle>0 ==> kp1 is xaxis (I suppose)
         Debug.log_image(f'anchor_{ind}', img)
예제 #7
0
 def draw_qr_area(self, image):
     if len(image.shape == 2):
         img_qr_area = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
     else:
         img_qr_area = image.copy()
     for kp in self.qr_anchor:
         cv.circle(img_qr_area, (kp.x, kp.y), int(kp.size / 2),
                   colors.BGR_GREEN, 1)
     cv.circle(img_qr_area, self.center, self.radius, colors.BGR_GREEN, 1)
     Debug.log_image('img_qr_area')
     return img_qr_area
예제 #8
0
def main_find_offset():
    MeterXy = collections.namedtuple('MeterXy', ['file_name', 'meter_id', 'code', 'x', 'y'])
    MeterOff = collections.namedtuple('MeterXy', ['file_name', 'meter_id', 'code', 'x', 'y', 'off_x', 'off_y'])

    folder = '../tmp/out/images/2019-08-08'

    # read meter_xy.csv
    with open(Cfg.xy_info_file, newline='') as csvfile:
        reader = csv.reader(csvfile, delimiter=',', quotechar='"')
        next(reader, None)  # skip headers
        meter_xy_list = [MeterXy(row[0], row[1], row[2], row[3], row[4]) for row in reader]

    shutil.rmtree(Cfg.log_folder, ignore_errors=True)
    os.makedirs(Cfg.log_folder, exist_ok=True)
    Debug.set_params(log_folder=Cfg.log_folder, log_image=Cfg.verbose)
    offsets = []
    for m in meter_xy_list:
        # if not str(m.file_name).endswith('447_v'):  # 554
        #     continue
        fname_path = f'{folder}/{m.file_name}.jpg'
        Debug.set_log_image_names(fname_path)

        off = find_offset(fname_path, (m.x, m.y), m.meter_id, m.code)
        offsets.append(MeterOff(m.file_name, m.meter_id, m.code, m.x, m.y, off[0], off[1]))
    offsets = sorted(offsets, key=lambda x: x.meter_id)
    print('offsets:\n\t', '\n\t'.join([f'{m.meter_id} : {m.file_name} : ({m.off_x:.5f},{m.off_y:.5f})  '
                                       f'xy:({m.x},{m.y})' for m in offsets if m.off_x != 9999.]), sep='')

    for meter_id in sorted(list(set([off.meter_id for off in offsets])), key=lambda x: int(x)):
        lst = [(m.off_x, m.off_y) for m in offsets if m.meter_id == meter_id and m.off_x != 9999]
        xy = [[l[i] for l in lst] for i in [0, 1]]
        # avg = (statistics.mean([l[0] for l in lst]), statistics.mean([l[0] for l in lst]))
        avg = (statistics.mean(xy[0]), statistics.mean(xy[1]))
        min_v = (min(xy[0]), min(xy[1]))
        max_v = (max(xy[0]), max(xy[1]))
        diff = (max_v[0] - min_v[0], max_v[1] - min_v[1])
        print(f'meter_id={meter_id} '
              f'avg=({avg[0]: .5f},{avg[1]: .5f}) '
              f'min=({min_v[0]: .5f},{min_v[1]: .5f}) '
              f'max=({max_v[0]: .5f},{max_v[1]: .5f})'
              f'diff=({diff[0]: .5f},{diff[1]: .5f})'
              )
예제 #9
0
def main():
    logger.debug('metering - start')
    Debug.set_params(log_folder=Cfg.log_folder, log_image=Cfg.log_image)
    if not os.path.isdir(Cfg.inp_folder):
        logger.error(f'Input folder {Cfg.inp_folder} does not exist.')
        return
    try:
        while True:
            if Cfg.need_sync:
                sync_meterings()
            files_list = sorted(
                glob.glob(f'{Cfg.inp_folder}/{Cfg.inp_fname_mask}'))
            if not len(files_list):
                if _GroupEquip.ready_to_analyze(event='empty_dir'):
                    Analyzer.run()
                logger.debug(f'timeout {Cfg.inp_timeout} sec')
                time.sleep(Cfg.inp_timeout)  # sec
                continue
            start = datetime.datetime.now()
            for (files_cnt, fname_path_flir) in enumerate(files_list, 1):

                cnt, meter_ids = take_readings(fname_path_flir)
                remove_input_files(fname_path_flir)

                if not cnt or not len(meter_ids):
                    continue  # skip it, no mark/equips/readings here
                logger.info(
                    f'{files_cnt} of {len(files_list)}: {fname_path_flir} readings:{cnt} '
                    f'equip:{list(set([Db.meter_to_equip(m) for m in meter_ids]))}'
                )

            seconds = (datetime.datetime.now() - start).seconds
            print(
                f'Processed {files_cnt} files in {seconds:.0f}s, ({seconds/files_cnt:.0f} sec/file)'
            )
            Db.close()
    except KeyboardInterrupt:
        logger.info('metering is interrupted by user')
        if _GroupEquip.ready_to_analyze(event='the_end'):
            Analyzer.run()
    finally:
        Db.close()
예제 #10
0
    def get_blob_keypoints(self):
        # input image --> list of blob keypoints
        params = cv.SimpleBlobDetector_Params()
        # Filter by Area.
        params.filterByArea = True
        params.minArea = MyMath.circle_area_by_diameter(Cfg.min_blob_diameter)

        # Set up the detector
        detector = cv.SimpleBlobDetector_create(params)
        # Detect blobs
        keypoints = detector.detect(self.image)
        # Draw detected blobs as red circles.
        # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
        img_with_keypoints = cv.drawKeypoints(self.image, keypoints, np.array([]), colors.BGR_BLUE,
                                              cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
        Debug.log_image('img_with_keypoints', img_with_keypoints)

        blob_keypoints = KeyPointList(blob_detector_keypoints_list=keypoints)
        logger.debug(f'keypoints found:{blob_keypoints}')
        return blob_keypoints
예제 #11
0
    def __init__(self, candidate_areas):
        self.image = candidate_areas.image
        self.areas = candidate_areas.candidate_qr_areas
        self.anchors = candidate_areas.anchors
        self.qr_decoded_marks = None

        # areas --> qr_decoded_marks:
        marks = []
        for ind in range(len(self.areas)):
            area, center, size, theta = self.areas[ind]
            pyzbar_objs = pyzbar.decode(area)
            if not len(pyzbar_objs):
                continue

            if len(pyzbar_objs) > 1:
                logger.info(f'Multiple codes ({len(pyzbar_objs)}) found in area {ind}')
                # skip it, definitely they should be found separately
                continue

            mark = QrMark(pyzbar_objs[0], area, self.anchors[ind], ind, center, size, theta)
            if self.area_ratio(mark, area, ind) < Cfg.min_area_ratio:
                logger.debug(f'found box area ratio is too small relatively to CandidateArea. Skipped. ind={ind}')
                continue

            marks.append(mark)
            Debug.log_image(f'found_{ind}_{mark.code}', mark.draw_box(area))
            # Debug.log_image(f'found_area_{ind}_{mark.code}', area)

        # duplicates rarely created if several triplets looks like anchor while referencing to the same qr code area
        # remove duplicates from marks:
        # for equal codes take one with the minimal area
        uniq_codes = list(set([m.code for m in marks]))  # list of unique codes from marks
        code_minareas = [(c, min([m.box_area for m in marks if m.code == c]))
                         for c in uniq_codes]  # list of tuples (code, min area for all marks with this code)
        # get items from marks which have minimal area for each uniq code
        self.qr_decoded_marks = [m for m in marks if (m.code, m.box.area()) in code_minareas]

        logger.debug(f'decoded marks list after removing duplicates:{self.qr_decoded_marks}]')
예제 #12
0
def take_readings(fname_path_flir):
    # file --> db + files in images/date
    Debug.set_log_image_names(fname_path_flir)

    try:
        fi = FlirImage(fname_path_flir)
    except (ValueError, KeyError):
        logger.exception(
            f'error while flir-processing file {fname_path_flir}. Skipped.')
        return 0, None
    qr_mark_list = QrDecode.get_all_qrs(fi.visual_img)

    visual_img_copy = fi.visual_img.copy()
    thermal_img_copy = fi.thermal_img.copy()

    reading_cnt = 0
    meter_ids = []
    for qr_mark in qr_mark_list:
        meter_records = Db.get_meters_from_db(qr_mark.code)
        if meter_records is None:
            logger.info(f'qrs_to_readings: no equips for qr_mark {qr_mark}')
            continue
        for meter_id, offset_x, offset_y in meter_records:
            meter_ids.append(meter_id)
            if offset_x == 9999.:
                continue
            logger.debug(f'take readings: meter_id={meter_id}: ')

            reading = Reading(meter_id, (offset_x, offset_y), qr_mark, fi)

            if reading.temperature is None:
                logger.error(
                    f'cannot create Reading '
                    f'for meter_id={meter_id} offset=({offset_x},{offset_y}) '
                    f'due to illegal coordinates after offset_to_xy()')
                continue

            if _GroupEquip.ready_to_analyze(event='readings_taken',
                                            meter_ids=meter_ids):
                Analyzer.run()

            reading.save_to_db()
            # reading.save_to_csv()

            # logger.debug(reading)
            reading.draw_visual(visual_img_copy)
            reading.draw_thermal(thermal_img_copy)
            Debug.log_image('visual_read', visual_img_copy)
            Debug.log_image('thermal_read', thermal_img_copy)
            reading_cnt += 1

    return reading_cnt, meter_ids
예제 #13
0
def process_file(fname_path):
    image0 = cv.imread(fname_path, cv.IMREAD_GRAYSCALE)
    Debug.log_image('image0')
    qr_list = QrDecode.get_all_qrs(image0)
    found = len(qr_list)  # cnt marks found
    return found