Найти новую координату после cv2.resize () - PullRequest
1 голос
/ 23 апреля 2019

Я подписан на 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 из 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(), чтобы получить значения new_h and new_w.Результат тот же.

Воспроизвести мой результат.
1. Оформите мою fork
2. Поместите файл в каталог data/demo/.Необработанное изображение ниже
3. Перейдите в корневой каталог проекта
4. pip install -r requirements.txt
5. python main/demo.py # Выполните с помощью Python3
6. python playground.py # Чтобы увидеть выходные данные накопия оригинала
Вот оригинальное изображение, если вы хотите попробовать original one

Этапы обработки изображения
1. Программа изменяет размер изображенияи сделать координаты boxes для меньшего.
2. Помеченные поля на скопированном изображении.
3. Запрограммируйте resize() результат обратно почти до исходного размера.

Проблема:
Выходная boxes координата на меньшем изображении не можетпреобразовать в правильную координату исходного с помощью функции наивного отображения.Чем больше ошибка, тем больше.

Вопрос:
Как я могу получить правильную координату моего пикселя после выполнения cv2.resize()?

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Когда вы пытаетесь инвертировать операцию изменения размера на ящиках, вы делите на rh и rw, но вы никогда не умножаете на h и w.

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

Это объясняет, почему ваша ошибка увеличивается с большими изображениями.

В качестве примечания вы можете использовать индексирование с нулевым индексом, чтобы избежать повторения каждой строки четыре раза:

z[:, 0::2] = h * z[:, 0::2] / rh
z[:, 1::2] = w * z[:, 1::2] / rw
0 голосов
/ 24 апреля 2019

Благодаря 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...