Reconhecimento de estradas por segmentação semântica

Na série anterior, conduzi um experimento com o movimento autônomo do meu tanque doméstico . A estrada foi reconhecida usando um filtro de cores e a máscara resultante foi para a entrada de uma rede neural classificadora especialmente treinada, que optou por ir para a direita, esquerda ou reta.

O ponto fraco foi o reconhecimento da própria rodovia devido à variabilidade das tonalidades das cores, pelas quais a rede neural de tomada de decisão produziu resultados estranhos. Os comentários sobre esse artigo recomendaram prestar atenção à segmentação semântica. O tópico mostrou-se promissor e o uso de redes neurais segmentadas trouxe suas vantagens, mas também suas desvantagens, onde estaria sem elas.

Mas as primeiras coisas primeiro e um pouco de equipamento.

Segmentação


A segmentação é o processo de destacar algumas partes de uma imagem. O tipo mais simples e óbvio de segmentação é a cor. No entanto, usando esse método, é impossível entender o que e onde está representado na figura.

Aqui está um bom artigo que descreve abordagens primitivas.

Segmentação semântica


Segmentação semântica - dividindo uma imagem em objetos com a determinação dos tipos desses objetos.

Parece algo como isto:



Os resultados são muito impressionantes, vamos ver o que vale a pena traduzir para a vida real.

U-net


A rede neural mais famosa, originalmente desenvolvida para medicina.
Fonte primária

As pessoas rapidamente perceberam que a abordagem pode ser usada para todas as ocasiões.

Existem muitos artigos na Internet sobre como preparar dados e treinar redes U-net:


No entanto, não encontrei uma rede U-net pronta para fazer e experimentar rapidamente.

E-net


Uma rede mais jovem e menos conhecida. Projetado apenas para reconhecer as ruas da cidade.


Dados


Os conjuntos de dados mais populares para segmentação de ruas (eles ensinaram inicialmente a E-net):


Nos mesmos conjuntos de dados, o U-net está sendo treinado.

Escolha de implementação


A enxurrada de novas informações sobre segmentação foi bastante esmagadora. Instintivamente, eu queria entender algo mais simples. Não senti o zen interno para entender a arquitetura das redes e passar um tempo aprendendo. Mas no artigo da PyImageSearch havia uma rede neural pronta e treinada, além disso, em um formato compatível com o OpenCV-DNN.

Portanto, a escolha foi feita em direção à menor resistência.

O uso é muito simples:
(O mais preocupante é que a rede é treinada em fotos de 1024x512 - isto é, primeiro, mais do que a câmera oferece no Raspberry e, segundo, o desempenho necessário para processar essa quantidade de dados é um pouco confuso. Como resultado, o principal problema será exatamente isso).

Lemos a rede neural a partir dos arquivos (em um, o próprio modelo, nos outros nomes de classe, nas terceiras cores).

def load_segment_model(): try: classes = None with open(PiConf.SEGMENT_CLASSES) as f: classes = f.read().strip().split("\n") colors = None with open(PiConf.SEGMENT_COLORS) as f: colors= f.read().strip().split("\n") colors = [np.array(c.split(",")).astype("int") for c in colors] colors = np.array(colors, dtype="uint8") print("[INFO] loading model...") net = cv2.dnn.readNet(PiConf.SEGMENT_MODEL) return net, classes, colors except Exception as e: logging.exception("Cannot load segment model") return None, None, None 

Segmentamos a imagem, marcando simultaneamente segmentos na parte superior da imagem original
(No meu caso, todas as classes, exceto a estrada, são invisíveis).

 def segment_image(image_path, seg_net, seg_classes, seg_colors): image0 = cv2.imread(image_path) image = cv2.resize(image0, (1024, 512),interpolation=cv2.INTER_NEAREST) blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (1024, 512), 0, swapRB=True, crop=False) seg_net.setInput(blob) start = time.time() output = seg_net.forward() end = time.time() print("[INFO] inference took {:.4f} seconds".format(end - start)) (numClasses, height, width) = output.shape[1:4] classMap = np.argmax(output[0], axis=0) mask = seg_colors[classMap] mask = cv2.resize(mask, (image0.shape[1], image0.shape[0]),interpolation=cv2.INTER_NEAREST) classMap = cv2.resize(classMap, (image0.shape[1], image0.shape[0]), interpolation=cv2.INTER_NEAREST) gmask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) gmask = cv2.resize(gmask, (128, 64), interpolation=cv2.INTER_NEAREST) gmask = gmask[0:64,32:96] output = ((0.6 * image0) + (0.4 * mask)).astype("uint8") return output, gmask 

Verifique


Tiramos fotos prontas do tanque e montamos uma rede neural segmentada sobre eles.

1



Somente o lado esquerdo da calçada é reconhecido como caro.

Comprimimos a imagem e tiramos dela um tamanho central de 64x64:
(Esse tamanho é esperado pela rede neural, que decide mudar de direção)



A rede neural da direção (de fato - o classificador) comanda para levar para a esquerda. Não muito correto, mas suportável.

2



Uma situação semelhante, novamente, o canto inferior direito é perdido (também há asfalto molhado).
No entanto, a maior parte da estrada ainda é reconhecida.



O classificador se oferece para seguir em frente.

3

A situação em que o robô estava no meio da calçada.



A estrada é reconhecida quase perfeitamente.



O classificador ordena que você vá para a direita (para encontrar a beira da estrada na próxima vez).

Aplicação


Tendo conjurado um pouco sobre o firmware do tanque, substituí o detector de estrada colorido por uma rede neural segmentada.

Ao lançar tudo isso no Raspberry Pi, a primeira coisa que saiu foi uma queda no desempenho.
Leva 6 segundos para segmentar uma imagem - durante esse período, o tanque consegue deslizar por todas as curvas com um trote vigoroso.

Em testes reais, isso aconteceu - apesar do reconhecimento quase perfeito da calçada e dos comandos corretos da rede neural de controle - durante o tempo em que a imagem foi processada, o tanque conseguiu se afastar.



Em geral, imagens desse tamanho não podem ser digeridas no Raspberry.
Parece que você ainda precisa fazer o treinamento de uma rede neural especializada.

Referências


Source: https://habr.com/ru/post/pt452088/


All Articles