在cv2.resize()

时间:2019-04-23 05:38:22

标签: python opencv image-processing

我正在关注text-detction-ctpn。该项目的作者resize()在进行计算之前先对图像进行处理。如果不调整图像大小,内存将耗尽。

通过此功能,我设法将调整后的尺寸框转换回原始尺寸的框

def transform_boxes(boxes: np.ndarray, h, w, rh, rw):
    """
    Transform back the original coordinate
    :param boxes:
    :param h: height of the original
    :param w: width of the original
    :param rh: re-sized height
    :param rw: re-sized height
    :return:
    """
    z = np.copy(boxes)
    z[:, 0] = z[:, 0] / rh
    z[:, 2] = z[:, 2] / rh
    z[:, 4] = z[:, 4] / rh
    z[:, 6] = z[:, 6] / rh

    z[:, 1] = z[:, 1] / rw
    z[:, 3] = z[:, 3] / rw
    z[:, 5] = z[:, 5] / rw
    z[:, 7] = z[:, 7] / rw

    return z

在大坐标数上,转换产生的错误非常明显 The original output calculation

Naive transform to original

更新
头撞后。我决定将代码放在这里。希望更多的眼睛可以帮助我发现错误。

# coding=utf-8
import os
import shutil
import sys
import time

import cv2
import numpy as np
import tensorflow as tf

from my_utils import draw_squares

sys.path.append(os.getcwd())
from nets import model_train as model
from utils.rpn_msr.proposal_layer import proposal_layer
from utils.text_connector.detectors import TextDetector

tf.app.flags.DEFINE_string('test_data_path', 'data/demo/', '')
tf.app.flags.DEFINE_string('output_path', 'data/res/', '')
tf.app.flags.DEFINE_string('gpu', '0', '')
tf.app.flags.DEFINE_string('checkpoint_path', 'checkpoints_mlt/', '')
FLAGS = tf.app.flags.FLAGS
from pprint import pprint


def transform_boxes(boxes: np.ndarray, im):
    """
    Transform back the original coordinate
    :param boxes:
    :param im: The original image
    :return:
    """
    z = np.copy(boxes)
    (height, width, colors) = im.shape
    new_h, new_w, img_size = get_new_wh(im)
    z[:, 0::2] = height * z[:, 0::2] / new_h
    z[:, 1::2] = width * z[:, 1::2] / new_w

    return z


def get_images():
    files = []
    exts = ['jpg', 'png', 'jpeg', 'JPG']
    for parent, dirnames, filenames in os.walk(FLAGS.test_data_path):
        for filename in filenames:
            for ext in exts:
                if filename.endswith(ext):
                    files.append(os.path.join(parent, filename))
                    break
    print('Find {} images'.format(len(files)))
    return files


def get_new_wh(img):
    """
    Get only new width and new height
    :param img:
    :return:
    """
    img_size = img.shape
    im_size_min = np.min(img_size[0:2])
    im_size_max = np.max(img_size[0:2])

    im_scale = float(600) / float(im_size_min)
    if np.round(im_scale * im_size_max) > 1200:
        im_scale = float(1200) / float(im_size_max)
    new_h = int(img_size[0] * im_scale)
    new_w = int(img_size[1] * im_scale)

    new_h = new_h if new_h // 16 == 0 else (new_h // 16 + 1) * 16
    new_w = new_w if new_w // 16 == 0 else (new_w // 16 + 1) * 16

    return new_h, new_w, img_size


def resize_image(img):
    new_h, new_w, img_size = get_new_wh(img)
    re_im = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    return re_im, (new_h / img_size[0], new_w / img_size[1])


def main(argv=None):
    if os.path.exists(FLAGS.output_path):
        shutil.rmtree(FLAGS.output_path)
    os.makedirs(FLAGS.output_path)
    os.environ['CUDA_VISIBLE_DEVICES'] = FLAGS.gpu

    with tf.get_default_graph().as_default():
        input_image = tf.placeholder(tf.float32, shape=[None, None, None, 3], name='input_image')
        input_im_info = tf.placeholder(tf.float32, shape=[None, 3], name='input_im_info')

        global_step = tf.get_variable('global_step', [], initializer=tf.constant_initializer(0), trainable=False)

        bbox_pred, cls_pred, cls_prob = model.model(input_image)

        variable_averages = tf.train.ExponentialMovingAverage(0.997, global_step)
        saver = tf.train.Saver(variable_averages.variables_to_restore())

        with tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) as sess:
            ckpt_state = tf.train.get_checkpoint_state(FLAGS.checkpoint_path)
            model_path = os.path.join(FLAGS.checkpoint_path, os.path.basename(ckpt_state.model_checkpoint_path))
            print('Restore from {}'.format(model_path))
            saver.restore(sess, model_path)

            im_fn_list = get_images()
            for im_fn in im_fn_list:
                print('===============')
                print(im_fn)
                start = time.time()
                try:
                    im = cv2.imread(im_fn)[:, :, ::-1]
                except:
                    print("Error reading image {}!".format(im_fn))
                    continue

                img, (rh, rw) = resize_image(im)
                h, w, c = img.shape
                im_info = np.array([h, w, c]).reshape([1, 3])
                bbox_pred_val, cls_prob_val = sess.run([bbox_pred, cls_prob],
                                                       feed_dict={input_image: [img],
                                                                  input_im_info: im_info})

                textsegs, _ = proposal_layer(cls_prob_val, bbox_pred_val, im_info)
                scores = textsegs[:, 0]
                textsegs = textsegs[:, 1:5]

                textdetector = TextDetector(DETECT_MODE='H')
                boxes = textdetector.detect(textsegs, scores[:, np.newaxis], img.shape[:2])
                boxes = np.array(boxes, dtype=np.int)

                new_boxes = transform_boxes(boxes, im)

                cost_time = (time.time() - start)
                print("cost time: {:.2f}s".format(cost_time))

                # The original output from re-sized picture
                # draw_squares(new_boxes, im, rh, rw, im_fn, scores, resize=False)
                draw_squares(new_boxes, im, im.shape[0], im.shape[1], im_fn, scores, resize=False)


if __name__ == '__main__':
    tf.app.run()

我看不到boxes的{​​{1}}输出。现在不是问题。我设法用demo.py画了红点。

playground.py

尽管我避免使用import os import cv2 import numpy as np import tensorflow as tf FLAGS = tf.app.flags.FLAGS def draw_squares(boxes, img, rh, rw, im_fn, scores, resize=True): for i, box in enumerate(boxes): cv2.polylines(img, [box[:8].astype(np.int32).reshape((-1, 1, 2))], True, color=(0, 255, 0), thickness=2) if resize: img = cv2.resize(img, None, None, fx=1.0 / rh, fy=1.0 / rw, interpolation=cv2.INTER_LINEAR) cv2.imwrite(os.path.join(FLAGS.output_path, os.path.basename(im_fn)), img[:, :, ::-1]) with open(os.path.join(FLAGS.output_path, os.path.splitext(os.path.basename(im_fn))[0]) + ".txt", "w") as f: for i, box in enumerate(boxes): line = ",".join(str(box[k]) for k in range(8)) line += "," + str(scores[i]) + "\r\n" f.writelines(line) ,因为它们被分割并且精度可能会损失。我使用rw, and rh来获取get_new_wh()值。结果是一样的。

要重现我的结果。
1.检出我的fork
2.将文件放入new_h and new_w目录。原始图片如下
3.将目录更改为根项目
4. data/demo/
5. pip install -r requirements.txt#使用Python3执行
6. python main/demo.py#在原始副本上查看输出
这是原始图片,如果您想尝试 original one

图像处理步骤
1.程序调整图片大小,并在较小的图片上建立python playground.py坐标。
2.在复制的图片上标记方框。
3.将boxes的结果编程为接近原始大小。

问题:
较小的图片上的输出resize()坐标无法使用朴素的映射功能转换为原始坐标的坐标。更大,更多错误。

问题:
boxes之后如何获得像素的正确坐标?

2 个答案:

答案 0 :(得分:1)

当您尝试颠倒包装盒上的调整大小操作时,用rhrw除,但不要乘以hw

z[:, 0] = h * z[:, 0] / rh
z[:, 1] = w * z[:, 1] / rw

这说明了为什么错误随着图像的增大而变得更大。

请注意,您可以使用numpy索引来避免每行重复四次:

z[:, 0::2] = h * z[:, 0::2] / rh
z[:, 1::2] = w * z[:, 1::2] / rw

答案 1 :(得分:0)

感谢Berak,我必须变换坐标而不是变换正在处理的像素。

  

坐标,而不是像素....

def transform_boxes(boxes: np.ndarray, im):
    """
    Transform back the original coordinate
    :param boxes:
    :param im: The original image
    :return:
    """
    z = np.copy(boxes)
    (height, width, colors) = im.shape
    new_h, new_w, img_size = get_float_new_wh(im)
    z[:, 0::2] = height * z[:, 0::2] / new_h
    z[:, 1::2] = width * z[:, 1::2] / new_w

    return z

def get_new_wh(img):
    """
    Get only new width and new height
    :param img:
    :return:
    """
    new_h, new_w, img_size = get_float_new_wh(img)
    new_h = int(new_h)
    new_w = int(new_w)

    new_h = new_h if new_h // 16 == 0 else (new_h // 16 + 1) * 16
    new_w = new_w if new_w // 16 == 0 else (new_w // 16 + 1) * 16
    return new_h, new_w, img_size

Final result