Как выделить часть массива из двумерного массива?

VolodinAS

Новичок
Пользователь
Дек 3, 2020
35
0
6
31
Россия, Тольятти
Указать свою операционную системуWINDOWS 10 x 64
Указать версию Python3.8.0
Укажите версию библиотек с которыми работаете
Код:
Package Version
-------------------------------- ---------
aiogram 2.11.2
aiohttp 3.6.3
altgraph 0.17
async-timeout 3.0.1
atomicwrites 1.4.0
attrs 20.3.0
Babel 2.9.0
beautifulsoup4 4.9.3
bindglobal 0.0.3
cattrs 1.1.2
certifi 2020.12.5
chardet 3.0.4
click 7.1.2
colorama 0.4.4
configparser 5.0.1
cycler 0.10.0
decorator 4.4.2
discord 1.0.1
discord.py 1.5.1
facebook-sdk 3.1.0
filetype 1.0.5
Flask 1.1.2
future 0.18.2
huepy 1.2.1
idna 2.10
imageio 2.9.0
imageio-ffmpeg 0.4.2
imutils 0.5.3
iniconfig 1.1.1
instabot 0.117.0
instagram-private-api 1.6.0.0
instagram-private-api-extensions 0.3.9
instapy-cli 0.0.12
itsdangerous 1.1.0
Jinja2 2.11.2
keybind 0.3.0
kiwisolver 1.3.1
MarkupSafe 1.1.1
matplotlib 3.3.3
mock 4.0.2
MouseInfo 0.1.3
moviepy 1.0.1
multidict 4.7.6
numpy 1.19.4
oauthlib 3.1.0
opencv-python 4.4.0.46
packaging 20.7
pefile 2019.4.18
Pillow 8.0.1
pip 20.3.1
playsound 1.2.2
pluggy 0.13.1
proglog 0.1.9
py 1.9.0
PyAutoGUI 0.9.52
PyGetWindow 0.0.9
pyinstaller 4.1
pyinstaller-hooks-contrib 2020.10
PyMsgBox 1.0.9
pynput 1.6.8
pyparsing 2.4.7
pyperclip 1.8.1
pypref 3.1.0
PyQt5 5.15.2
PyQt5-sip 12.8.1
PyQt5-stubs 5.14.2.2
PyRect 0.1.4
PyScreeze 0.1.26
PySocks 1.7.1
pyTelegramBotAPI 3.7.4
pytest 6.1.2
python-dateutil 2.8.1
python-facebook-api 0.7.2
python-xlib 0.29
PyTweening 1.0.3
pytz 2020.4
pywin32-ctypes 0.2.0
requests 2.25.0
requests-oauthlib 1.3.0
requests-toolbelt 0.9.1
responses 0.11.0
schedule 0.6.0
scipy 1.5.4
setuptools 50.3.2
six 1.15.0
soupsieve 2.0.1
toml 0.10.2
tqdm 4.54.1
typing-extensions 3.7.4.3
urllib3 1.26.2
vk 2.0.2
vk-api 11.9.1
Werkzeug 1.0.1
yarl 1.5.1
Вставьте фрагмент кода который у вас имеется на данный моментОписание вопроса ниже

Итак, осваиваю нейронные сети, решил начать с небольших капч.
Пример капчи:
1608189604875.png

В чем суть. На капче есть 2 числа. Мне нужно получить 2 массива - NumberFirst и NumberSecond, в каждом из них будет массив из 0 и 1.

Как я пытаюсь это сделать:

С помощью некоторой обработки изображений получаю вот это:
1608189656542.png

Перевожу эти черно-белые данные в байтовых двумерный массив.
1608189713114.png

Теперь мне нужно вычленить только те данные, где есть числа. Для этого сначала я транспонирую эту матрицу:
Python:
# Транспонирование в одну сторону
NumbersTransponire = [list(i) for i in zip(*Numbers)]

1608189800099.png

Теперь я пробегаюсь по каждой строчке и ищу, в какой из них суммарно больше 3х единиц:

Python:
NumberFirst = []
NumberSecond = []
flag_findFirst = False
flag_findSecond = False
index_firstNumber_begin = -1
index_firstNumber_end = -1
index_secondNumber_begin = -1
index_secondNumber_end = -1

rowIndex = 0
for row in NumbersTransponire:
    col_summ = sum(row)
    print(col_summ)
    RowArray = []
    if col_summ >= 3:
        if index_firstNumber_begin == -1:
            index_firstNumber_begin = rowIndex
            NumberFirst.append(RowArray)
        else:
            if index_firstNumber_end == -1:
                NumberFirst.append(RowArray)
            else:
                if index_secondNumber_begin == -1:
                    index_secondNumber_begin = rowIndex
                    NumberSecond.append(RowArray)
                else:
                    if index_secondNumber_end == -1:
                        NumberSecond.append(RowArray)
    else:
        if index_firstNumber_begin > -1:
            index_firstNumber_end = rowIndex - 1
        else:
            if index_secondNumber_begin > -1:
                index_secondNumber_end = rowIndex - 1
0
2
1
4
6
5
9
10
10
8
11
13
9
3
1
3
0
0
0
2
4
9
12
10
10
10
6
4
4
4
3
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
▲ видно границы начала и конца чисел ▲

А главный вопрос: может я занимаюсь изобретением велосипеда? Может быть уже есть готовое решение? Суть такая - из одного большого массива получить два, где сумма элементов больше или равна 3? Вполне вероятно, это вообще решается одной строчкой, только вот я об этом не знаю...
 
Последнее редактирование:

VolodinAS

Новичок
Пользователь
Дек 3, 2020
35
0
6
31
Россия, Тольятти
Задача даже больше расширяется. Есть капча, где сумма элементов в первом ряду равна 5, но тем не менее, изображением не является:
1608193632083.png

При транспонировании:
1608193659418.png

Получается, нужно прогнать еще каждый столбец, чтобы найти места, где подряд есть 3 элемента:
Python:
ThreeInRow = []
        for col in row:
            if len(ThreeInRow) < 3:
                ThreeInRow.append(col)
            else:
                if sum(ThreeInRow) >= 3:
                    flag_Append = True
                    break
                ThreeInRow = []

Но этот триггер должен срабатывать не всегда, а только тогда, когда итератор находится в границах числа...

Я не могу понять, как это всё осуществить...

UPD. Немного довёл до ума. Догадался, что подряд три единицы можно найти через find, преобразовав список в строку:
Python:
rowIndex = 0
    ThreeInRow = []
    for row in NumbersTransponire:
        flag_Append = False

        ThreeInRow_string = linear_array2string(row, '')
        if ThreeInRow_string.find('111') > -1:
            flag_Append = True
        ThreeInRow = []

        col_summ = sum(row)

        print(f"[{rowIndex}], col_summ={col_summ}, flag_Append={flag_Append}, ThreeInRow_string={ThreeInRow_string}")

        rowIndex += 1
[0], col_summ=5, flag_Append=False, ThreeInRow_string=0010000000000100010101000000000000000000
[1], col_summ=1, flag_Append=False, ThreeInRow_string=0000000000100000000000000000000000000000
[2], col_summ=3, flag_Append=False, ThreeInRow_string=0000000110000000000010000000000000000000
[3], col_summ=7, flag_Append=True, ThreeInRow_string=0000100111000100011000000000000000000000
[4], col_summ=11, flag_Append=True, ThreeInRow_string=0000001101010011111101000000000000000000
[5], col_summ=10, flag_Append=True, ThreeInRow_string=0000000111010111101100000000000000000000
[6], col_summ=13, flag_Append=True, ThreeInRow_string=0000000111111110111110000000000000000000
[7], col_summ=10, flag_Append=True, ThreeInRow_string=0000000011111011111000000000000000000000
[8], col_summ=9, flag_Append=True, ThreeInRow_string=0000000010111111110000000000000000000000
[9], col_summ=6, flag_Append=True, ThreeInRow_string=0000000010011110100000000000000000000000
[10], col_summ=5, flag_Append=True, ThreeInRow_string=0000000011111000000000000000000000000000
[11], col_summ=3, flag_Append=False, ThreeInRow_string=0000000000100101000000000000000000000000
[12], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[13], col_summ=1, flag_Append=False, ThreeInRow_string=0000000000001000000000000000000000000000
[14], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[15], col_summ=1, flag_Append=False, ThreeInRow_string=0000000000000010000000000000000000000000
[16], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[17], col_summ=1, flag_Append=False, ThreeInRow_string=0000000000010000000000000000000000000000
[18], col_summ=3, flag_Append=True, ThreeInRow_string=0000000000111000000000000000000000000000
[19], col_summ=5, flag_Append=True, ThreeInRow_string=0000000000111001010000000000000000000000
[20], col_summ=7, flag_Append=True, ThreeInRow_string=0000000000111100000011100000000000000000
[21], col_summ=10, flag_Append=True, ThreeInRow_string=0000000000011100011111110000000000000000
[22], col_summ=9, flag_Append=True, ThreeInRow_string=0000000000010100111110011000000000000000
[23], col_summ=9, flag_Append=True, ThreeInRow_string=0000000000010101111000111000000000000000
[24], col_summ=10, flag_Append=True, ThreeInRow_string=0000000000010111100011111000000000000000
[25], col_summ=11, flag_Append=True, ThreeInRow_string=0000000000011111001111110000000000000000
[26], col_summ=6, flag_Append=True, ThreeInRow_string=0000000000001000111110000000000000000000
[27], col_summ=7, flag_Append=True, ThreeInRow_string=0000000000001111111000000000000000000000
[28], col_summ=4, flag_Append=True, ThreeInRow_string=0000000000001111000000000000000000000000
[29], col_summ=3, flag_Append=True, ThreeInRow_string=0000000000000111000000000000000000000000
[30], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[31], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[32], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[33], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[34], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[35], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[36], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[37], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[38], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[39], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[40], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[41], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[42], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[43], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[44], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[45], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[46], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[47], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[48], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
[49], col_summ=0, flag_Append=False, ThreeInRow_string=0000000000000000000000000000000000000000
 
Последнее редактирование:

VolodinAS

Новичок
Пользователь
Дек 3, 2020
35
0
6
31
Россия, Тольятти
В общем, посидел, подумал и всё-таки получилось.
Вот код функции:
Python:
def arrayCutter(arr, good_values=1, in_row=3, summ=3, offset=0):
    cutter = {
        'data': [],
        'index_begin': -1,
        'index_end': -1
    }

    flag_begin = flag_end = False

    temp = ''
    for i in range(in_row):
        temp += str(good_values)

    rowIndex = 0
    data = []
    index_begin = -1
    index_end = -1
    for i in range(offset, len(arr)):
        flag_Append = False
        row = arr[i]
        col_summ = sum(row)

        tinr = linear_array2string(row, '')
        if tinr.find(temp) > -1:
            flag_Append = True

        if not flag_begin:
            if flag_Append and col_summ >= summ:
                flag_begin = True
                index_begin = i
                data.append(row)
        else:
            if not flag_end:
                if col_summ == 0: # измененное условие
                    flag_end = False
                    index_end = i-1
                    break
                else:
                    data.append(row)

        # print(
        #     f"[{rowIndex}] col_summ={col_summ}, flag_Append={flag_Append}, begin={flag_begin}, end={flag_end}, ib={index_begin}, ie={index_end}")
        # print(row)
        # print('')

        rowIndex += 1

    cutter['data'] = data
    cutter['index_begin'] = index_begin
    cutter['index_end'] = index_end

    return cutter

Она возвращает словарь с элементами data (сам чистый массив с числом), index_begin и index_end - индексы начала и конца числа соответственно.

Ее отличие в том, что она ищет только одно число из двух. Второе число - находится путём указания конца индекса первого:
Python:
    NumberFirst = arrayCutter(NumbersTransponire, good_values=1, in_row=2, summ=2, offset=0)
    NumberSecond = arrayCutter(NumbersTransponire, good_values=1, in_row=2, summ=2, offset=NumberFirst['index_end']+1)

Плюс ко всему я инвертировал условия - сначала должна быть проверка - начат ли поиск начала числа? Если нет - ничего не делать, если да - добавлять всё, пока не будут нули в суммах

Вот результат работы:
1608198181539.png

1608198206820.png

1608198231248.png

1608198257229.png

Думаю, продолжу работать в этой стезе дальше...
 

VolodinAS

Новичок
Пользователь
Дек 3, 2020
35
0
6
31
Россия, Тольятти
В общем, я понял, что велосипед изобретать бессмысленно. Решил начать всё сначала.
Нашел метод findContours в библиотеке openCV
Вот код:
Python:
from PIL import Image
import pytesseract
import cv2
import os
import pyscreenshot as ps
import numpy as np
import time
import sys
import random
from CoolFilePathParser import CFPP
from Config import Config
from jprint import jprint
from imagelab import image_lab_file, image_lab_image
import json

window_width = 400
window_height = 300


def get_contour_precedence(contour, cols):
    tolerance_factor = 10
    origin = cv2.boundingRect(contour)
    return ((origin[1] // tolerance_factor) * tolerance_factor) * cols + origin[0]


def get_random_file():
    numbers_dirs = os.listdir(Config.collections_dir)
    random.shuffle(numbers_dirs)
    number_path = Config.collections_dir + '/' + numbers_dirs[0]
    captcha_dirs = os.listdir(number_path)
    random.shuffle(captcha_dirs)
    captcha_name = captcha_dirs[0]
    return str(number_path + '/' + captcha_name)


dark41_file = Config.testcaptcha_dir + '/dark41.jpg'
light41_file = Config.testcaptcha_dir + '/light41.jpg'

captcha_path = get_random_file()

print(captcha_path)

cfpp = CFPP(captcha_path)
ParsePath = cfpp.get_cleanData
jprint(ParsePath, 'ParsePath')

# Оригинал изображения
image_light41 = cv2.imread(captcha_path, cv2.IMREAD_COLOR)
image_light41_big = cv2.resize(image_light41, (window_width, window_height))
cv2.imshow('image_light41_big', image_light41_big)

# Контрастируем через LAB
image_light41_lab = image_lab_file(filename=captcha_path)
image_light41_lab_gray = cv2.cvtColor(image_light41_lab, cv2.COLOR_RGB2GRAY)
image_light41_lab_gray_big = cv2.resize(image_light41_lab_gray, (window_width, window_height))
cv2.imshow('image_light41_lab_gray_big', image_light41_lab_gray_big)

# Убираем шумы
se = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))
bg = cv2.morphologyEx(image_light41_lab_gray_big, cv2.MORPH_DILATE, se)
out_gray = cv2.divide(image_light41_lab_gray_big, bg, scale=255)
cv2.imshow('out_gray', out_gray)

out_binary = cv2.threshold(out_gray, 0, 255, cv2.THRESH_OTSU)[1]
cv2.imshow('out_binary', out_binary)

# Выделяем контуры
rgb = cv2.cvtColor(out_binary, cv2.COLOR_GRAY2RGB)
cv2.imshow('rgb COLOR_GRAY2RGB', rgb)

hsv = cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)
cv2.imshow('hsv COLOR_RGB2HSV', hsv)

hsv_min = np.array((0, 0, 0), np.uint8)
hsv_max = np.array((20, 20, 20), np.uint8)

thresh = cv2.inRange(hsv, hsv_min, hsv_max)
contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

image_light41_big_sort = image_light41_big.copy()
image_light41_big_sort_2 = image_light41_big.copy()

cv2.drawContours(image_light41_big, contours, -1, (255, 0, 0), 1, cv2.LINE_AA, hierarchy, 1)
cv2.imshow('contours', image_light41_big)  # выводим итоговое изображение в окно

cv2.waitKey(0)
cv2.destroyAllWindows()
Вот результат работы:
1608243774670.png

На окне contours выделено два основных контура.
Искал способ их выделения - так и не нашел
В общем - как мне обрезать изображение по контуру? Причем, я так понимаю, надо отсортировать контуры и выбрать только два, самых крупных. Как это сделать?
 

Форум IT Специалистов