Home › Fóruns › Fórum Rastreamento de Objetos com Python e OpenCV › Transformar “máscara” em vídeo
- Este tópico contém 9 respostas, 2 vozes e foi atualizado pela última vez 2 anos, 12 meses atrás por
Dalton Vargas.
- AutorPosts
- 2 de março de 2022 às 19:28 #33632
Boa tarde , me chamo Pedro Henrique, sou assinante da IA Expert (inclusive, gostaria de comentar que o curso é excelente), venho por meio deste fórum perguntar se alguém poderia me auxiliar com uma dúvida. No caso, estou tentando mesclar codificações das aulas de detecção de movimento e de rastreamento de objetos, utilizando python e openCV. Bom , minha dúvida é o seguinte, queria saber se é possível aplicar os parâmetros de shitomasi e lucas kanade em uma máscara retirada de um algoritmo de subtração de background, já estou tentando fazer essa junção, porém não consigo fazer com que o algoritmo shitomasi-kanade “leia” a máscara obtida como um vídeo.
cap = cv2.VideoCapture("result")
(sendo “result” a máscara do algoritmo de subtração)
Para um entendimento mais fácil da situação, estou enviando o código.
import numpy as np import cv2 import sys ################################################################################## # Escolha do Vídeo VIDEO_SOURCE = "videos/Video_5.mp4" #Definindo as variáveis de cor/fonte TEXT_COLOR = (0, 255, 0) TRACKER_COLOR = (255, 0, 0) FONT = cv2.FONT_HERSHEY_SIMPLEX # Escolha do Background BGS_TYPES = ["MOG2", "KNN"] BGS_TYPE = BGS_TYPES[1] ################################################################################## # Escolha do Kernel def getKernel(KERNEL_TYPE): if KERNEL_TYPE == "dilation": kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) if KERNEL_TYPE == "opening": kernel = np.ones((3,3), np.uint8) if KERNEL_TYPE == "closing": kernel = np.ones((3,3), np.uint8) return kernel ################################################################################## # Criação dos Filtros def getFilter(img, filter): if filter == 'closing': return cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) if filter == 'opening': return cv2.morphologyEx(img, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) if filter == 'dilation': return cv2.dilate(img, getKernel("dilation"), iterations=2) if filter =='combine': closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) dilation = cv2.dilate(opening, getKernel("dilation"), iterations=2) return dilation ################################################################################## def getBGSubtractor(BGS_TYPE): if BGS_TYPE == "MOG2": return cv2.createBackgroundSubtractorMOG2() if BGS_TYPE == "KNN": return cv2.createBackgroundSubtractorKNN() print("Detector inválido") sys.exit(1) cap = cv2.VideoCapture(VIDEO_SOURCE) bg_subtractor = getBGSubtractor(BGS_TYPE) minArea = 150 ################################################################################## # Configuração dos parametros Shitomasi e Lucas Kanade def SK(result): cap = cv2.VideoCapture("result") parameters_shitomasi = dict(maxCorners=100, # máx de nós qualityLevel=0.05, # aumenta pra achar mais e diminui pra achar menos minDistance=30) # distancia entre pontos parameters_lucas_kanade = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.05)) colors = np.random.randint(0, 255, (100, 3)) ret, frameSK = cap.read() frame_gray_init = cv2.cvtColor(frameSK, cv2.COLOR_BGR2GRAY) edges = cv2.goodFeaturesToTrack(frame_gray_init, mask=None, **parameters_shitomasi) # print(edges) #localização dos pontos inicias marcados print(len(edges)) # contagem de pontos indentificados maskSK = np.zeros_like(frameSK) # print(maskSK) # print(np.shape(maskSK)) #dimensão do vídeo while True: ret, frameSK = cap.read() frame_gray = cv2.cvtColor(frameSK, cv2.COLOR_BGR2GRAY) new_edges, status, errors = cv2.calcOpticalFlowPyrLK(frame_gray_init, frame_gray, edges, None, **parameters_lucas_kanade) news = new_edges[status == 1] olds = edges[status == 1] for i, (new, old) in enumerate(zip(news, olds)): a, b = new.ravel() c, d = old.ravel() a, b, c, d = int(a), int(b), int(c), int(d) maskSK = cv2.line(maskSK, (a, b), (c, d), colors[i].tolist(), 2) frameSK = cv2.circle(frameSK, (a, b), 5, colors[i].tolist(), -1) img = cv2.add(frameSK, maskSK) cv2.imshow('Optical flow', img) # cv2.imshow('maskSK',maskSK) # cv2.imshow('frameSK',frameSK) if cv2.waitKey(1) == 13: break frame_gray_init = frame_gray.copy() edges = news.reshape(-1, 1, 2) cv2.destroyAllWindows() cap.release() ################################################################################## def main(): while (cap.isOpened): ok,frameBG = cap.read() if not ok: print("ERRO") break frameBG = cv2.resize(frameBG, (0,0), fx=0.50, fy=0.50) bg_mask = bg_subtractor.apply(frameBG) bg_mask = getFilter(bg_mask,'combine') bg_mask = cv2.medianBlur(bg_mask, 5) #################################################################################################### # Aplicação dos contornos (contours, hierarchy) = cv2.findContours(bg_mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: area = cv2.contourArea(cnt) if area>= minArea: x,y,w,h = cv2.boundingRect(cnt) cv2.drawContours(frameBG, [cnt], -1, TRACKER_COLOR, 2) cv2.drawContours(frameBG, [cnt], -1, (255, 255, 255), 1) #################################################################################################### result = cv2.bitwise_and(frameBG,frameBG,mask=bg_mask) #cv2.imshow('frameBG', frameBG) #cv2.imshow('Mask', result) #################################################################################################### # Aplicação dos parametros shitomasi e kanade SK(result) #################################################################################################### # Configuração da tecla de saída #if cv2.waitKey(1) & 0xFF == ord("q"): # break if cv2.waitKey(1) == 13: break # Liberação das janelas de vídeo cv2.destroyAllWindows() cap.release() # Acionamento do main() main()
3 de março de 2022 às 07:25 #33635Olá Pedro!
Parabéns pela ideia do projeto, é bem interessante!
Pelo que entendi, a ideia é aplicar o algoritmo subtrator de fundo e depois usar o resultado para o algoritmo Optical Flow rastrear, seria isto?
Se sim, pelos fontes que você mandou, você estava chegando lá, só faltavam ajustar os parâmetros das imagens usadas entre os dois algoritmos.
Fiz uma implementação simples baseada nesta ideia, vou mandar na próxima resposta aqui. Provavelmente você terá que ajustar os parâmetros de cada algoritmo de acordo com seu projeto, pois deixei a parametrização padrão de cada um.
3 de março de 2022 às 07:26 #33636import numpy as np import cv2 import sys from random import randint # Criar um vetor para gerar cores aleatoriamente (R,G,B) TEXT_COLOR = (randint(0, 255), randint(0, 255), randint(0, 255)) BORDER_COLOR = (randint(0, 255), randint(0, 255), randint(0, 255)) FONT = cv2.FONT_HERSHEY_SIMPLEX VIDEO_SOURCE = "videos/walking.avi" # vetor de background subtractors BGS_TYPES = ["GMG", "MOG", "MOG2", "KNN", "CNT"] # definir qual BGS usar, inserindo o número que corresponde ao BGS selecionado no vetor de background subtractors # 0 = GMG, 1 = MOG, 2 = MOG2, 3 = KNN, 4 = CNT BGS_TYPE = BGS_TYPES[2] # Kernel: Elemento estruturante def getKernel(KERNEL_TYPE): if KERNEL_TYPE == "dilation": kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) if KERNEL_TYPE == "opening": kernel = np.ones((3, 3), np.uint8) if KERNEL_TYPE == "closing": kernel = np.ones((3, 3), np.uint8) return kernel # Filtros morfológicos para redução do ruído def getFilter(img, filter): ''' Esses filtros são escolhidos a dedo, apenas com base em testes visuais ''' if filter == 'closing': return cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) if filter == 'opening': return cv2.morphologyEx(img, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) if filter == 'dilation': return cv2.dilate(img, getKernel("dilation"), iterations=2) if filter == 'combine': closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) dilation = cv2.dilate(opening, getKernel("dilation"), iterations=2) return dilation def getBGSubtractor(BGS_TYPE): if BGS_TYPE == "GMG": return cv2.bgsegm.createBackgroundSubtractorGMG(initializationFrames=120, decisionThreshold=.8) if BGS_TYPE == "MOG": return cv2.bgsegm.createBackgroundSubtractorMOG(history=200, nmixtures=5, backgroundRatio=.7, noiseSigma=0) if BGS_TYPE == "MOG2": return cv2.createBackgroundSubtractorMOG2(history=500, detectShadows=True, varThreshold=100) if BGS_TYPE == "KNN": return cv2.createBackgroundSubtractorKNN(history=500, dist2Threshold=400, detectShadows=True) if BGS_TYPE == "CNT": return cv2.bgsegm.createBackgroundSubtractorCNT(minPixelStability=15, useHistory=True, maxPixelStability=15*60, isParallel=True) print("Unknown createBackgroundSubtractor type") sys.exit(1) # Carregar o video cap = cv2.VideoCapture(VIDEO_SOURCE) bg_subtractor = getBGSubtractor(BGS_TYPE) def SubtractorTracker(): # Inicialização do TRACKER parameters_shitomasi = dict(maxCorners = 100, qualityLevel = 0.3, minDistance = 7) parameters_lucas_kanade = dict(winSize = (15, 15), maxLevel = 2, criteria = (cv2.TERM_CRITERIA_EPS | cv2. TERM_CRITERIA_COUNT, 10, 0.03)) colors = np.random.randint(0,255, (100, 3)) ret, frame = cap.read() frame_gray_init = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) edges = cv2.goodFeaturesToTrack(frame_gray_init, mask = None, **parameters_shitomasi) mask = np.zeros_like(frame) while (cap.isOpened): ok, frame = cap.read() if not ok: print("Frame capture failed, stopping...") break bg_mask = bg_subtractor.apply(frame) fg_mask = getFilter(bg_mask, 'combine') # Resultado da subtração de fundo result = cv2.bitwise_and(frame, frame, mask=fg_mask) # Passamos como parâmetro ao Tracker o resultado do BGS frame_gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY) new_edges, status, errors = cv2.calcOpticalFlowPyrLK(frame_gray_init, frame_gray, edges, None, **parameters_lucas_kanade) news = new_edges[status == 1] olds = edges[status == 1] for i, (new, old) in enumerate(zip(news, olds)): a, b = new.ravel() c, d = old.ravel() mask = cv2.line(mask, (a,b), (c,d), colors[i].tolist(), 2) frame = cv2.circle(result, (a,b), 5, colors[i].tolist(), -1) img = cv2.add(result, mask) cv2.imshow('BGS + Optical flow', img) if cv2.waitKey(1) == 13: break frame_gray_init = frame_gray.copy() edges = news.reshape(-1,1,2) SubtractorTracker()
- Esta resposta foi modificada 3 anos atrás por
Dalton Vargas.
7 de março de 2022 às 14:11 #33678Olá Dalton, com o seu algoritmo consegui avançar um pouco, consigo até visualizar a tela preta com as linhas formadas, porém a janela trava e não consigo rodar o vídeo, acabei obtendo outro problema que foge do meu conhecimento, normalmente eu pesquiso mas não entendi oque realmente é esse erro. No caso o erro é o seguinte:
Traceback (most recent call last):
File “C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2800.0_x64__qbz5n2kfra8p0\lib\code.py”, line 90, in runcode
exec(code, self.locals)
File “<input>”, line 1, in <module>
File “C:\Program Files\JetBrains\PyCharm 2021.3.1\plugins\python\helpers\pydev\_pydev_bundle\pydev_umd.py”, line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File “C:\Program Files\JetBrains\PyCharm 2021.3.1\plugins\python\helpers\pydev\_pydev_imps\_pydev_execfile.py”, line 18, in execfile
exec(compile(contents+”\n”, file, ‘exec’), glob, loc)
File “C:/Users/pedro/PycharmProjects/pythonProject1/TESTE IA.py”, line 132, in <module>
SubtractorTracker()
File “C:/Users/pedro/PycharmProjects/pythonProject1/TESTE IA.py”, line 109, in SubtractorTracker
news = new_edges[status == 1]
TypeError: ‘NoneType’ object is not subscriptableDesculpe ficar pedindo ajuda, mas se puder me auxiliar, ficarei muito agradecido.
9 de março de 2022 às 11:23 #33690Pedro,
poderia compartilhar o fonte completo? Assim consigo analisar e testar aqui também.
Ah e quando for mandar o fonte, por favor não esqueça de mandar em uma mensagem separada, adicionando como bloco de código, assim o script não perde a formatação original.
- Esta resposta foi modificada 3 anos atrás por
Dalton Vargas.
11 de março de 2022 às 15:59 #33706Oi Dalton, consigo sim.
import numpy as np import cv2 import sys from random import randint ################################################################################## # Escolha do Vídeo VIDEO_SOURCE = "videos/Video_5.mp4" #Definindo as variáveis de cor/fonte aleatoriamente (R,G,B) TEXT_COLOR = (randint(0, 255), randint(0,255),randint(0,255)) TRACKER_COLOR = (randint(0, 255), randint(0,255),randint(0,255)) FONT = cv2.FONT_HERSHEY_SIMPLEX # Escolha do Background BGS_TYPES = ["MOG2", "KNN"] BGS_TYPE = BGS_TYPES[1] ################################################################################## # Escolha do Kernel def getKernel(KERNEL_TYPE): if KERNEL_TYPE == "dilation": kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) if KERNEL_TYPE == "opening": kernel = np.ones((3,3), np.uint8) if KERNEL_TYPE == "closing": kernel = np.ones((3,3), np.uint8) return kernel ################################################################################## # Criação dos Filtros def getFilter(img, filter): if filter == 'closing': return cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) if filter == 'opening': return cv2.morphologyEx(img, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) if filter == 'dilation': return cv2.dilate(img, getKernel("dilation"), iterations=2) if filter =='combine': closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) dilation = cv2.dilate(opening, getKernel("dilation"), iterations=2) return dilation ################################################################################## def getBGSubtractor(BGS_TYPE): if BGS_TYPE == "MOG2": return cv2.createBackgroundSubtractorMOG2() if BGS_TYPE == "KNN": return cv2.createBackgroundSubtractorKNN() print("Detector inválido") sys.exit(1) ################################################################################## # Carregando o vídeo cap = cv2.VideoCapture(VIDEO_SOURCE) bg_subtractor = getBGSubtractor(BGS_TYPE) minArea = 150 ################################################################################## # Configuração dos parametros Shitomasi e Lucas Kanade def SK(): parameters_shitomasi = dict(maxCorners=100, # máx de nós qualityLevel=0.05, # aumenta pra achar mais e diminui pra achar menos minDistance=30) # distancia entre pontos parameters_lucas_kanade = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.05)) colors = np.random.randint(0, 255, (100, 3)) ret, frame = cap.read() frame_gray_init = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) edges = cv2.goodFeaturesToTrack(frame_gray_init, mask=None, **parameters_shitomasi) mask = np.zeros_like(frame) # print(edges) #localização dos pontos inicias marcados print(len(edges)) # contagem de pontos indentificados # print(mask) # print(np.shape(mask)) #dimensão do vídeo while (cap.isOpened): ok, frame = cap.read() if not ok: print("ERRO...") break bg_mask = bg_subtractor.apply(frame) fg_mask = getFilter(bg_mask, 'combine') # Resultado da subtração de fundo result = cv2.bitwise_and(frame, frame, mask=fg_mask) # Passamos como parâmetro ao Tracker o resultado do BGS frame_gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY) new_edges, status, errors = cv2.calcOpticalFlowPyrLK(frame_gray_init, frame_gray, edges, None, **parameters_lucas_kanade) news = new_edges[status == 1] olds = edges[status == 1] for i, (new, old) in enumerate(zip(news, olds)): a, b = new.ravel() c, d = old.ravel() a, b, c, d = int(a), int(b), int(c), int(d) mask = cv2.line(mask, (a, b), (c, d), colors[i].tolist(), 2) frame = cv2.circle(frame, (a, b), 5, colors[i].tolist(), -1) img = cv2.add(result, mask) cv2.imshow('BGS + Optical flow', img) if cv2.waitKey(1) == 13: break frame_gray_init = frame_gray.copy() edges = news.reshape(-1, 1, 2) cv2.destroyAllWindows() cap.release() # Acionamento do main() SK() ################################################################################## ERRO: Traceback (most recent call last): File "C:\Users\Pedro Henrique\PycharmProjects\IC\main.py", line 137, in <module> SK() File "C:\Users\Pedro Henrique\PycharmProjects\IC\main.py", line 109, in SK news = new_edges[status == 1] TypeError: 'NoneType' object is not subscriptable
13 de março de 2022 às 08:27 #33715Opa!
Fiz a correção e teste com seu script, segue o link de um vídeo de demontração:
Na próxima mensagem vou postar o script.
13 de março de 2022 às 08:28 #33716import numpy as np import cv2 import sys from random import randint ################################################################################## # Escolha do Vídeo VIDEO_SOURCE = "videos/persons.mp4" #Definindo as variáveis de cor/fonte aleatoriamente (R,G,B) TEXT_COLOR = (randint(0, 255), randint(0,255),randint(0,255)) TRACKER_COLOR = (randint(0, 255), randint(0,255),randint(0,255)) FONT = cv2.FONT_HERSHEY_SIMPLEX # Escolha do Background BGS_TYPES = ["MOG2", "KNN"] BGS_TYPE = BGS_TYPES[1] ################################################################################## # Escolha do Kernel def getKernel(KERNEL_TYPE): if KERNEL_TYPE == "dilation": kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) if KERNEL_TYPE == "opening": kernel = np.ones((3,3), np.uint8) if KERNEL_TYPE == "closing": kernel = np.ones((3,3), np.uint8) return kernel ################################################################################## # Criação dos Filtros def getFilter(img, filter): if filter == 'closing': return cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) if filter == 'opening': return cv2.morphologyEx(img, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) if filter == 'dilation': return cv2.dilate(img, getKernel("dilation"), iterations=2) if filter =='combine': closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, getKernel("closing"), iterations=2) opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, getKernel("opening"), iterations=2) dilation = cv2.dilate(opening, getKernel("dilation"), iterations=2) return dilation ################################################################################## def getBGSubtractor(BGS_TYPE): if BGS_TYPE == "MOG2": return cv2.createBackgroundSubtractorMOG2() if BGS_TYPE == "KNN": return cv2.createBackgroundSubtractorKNN() print("Detector inválido") sys.exit(1) ################################################################################## # Carregando o vídeo cap = cv2.VideoCapture(VIDEO_SOURCE) bg_subtractor = getBGSubtractor(BGS_TYPE) minArea = 150 ################################################################################## # Configuração dos parametros Shitomasi e Lucas Kanade def SK(): parameters_shitomasi = dict(maxCorners=100, # máx de nós qualityLevel=0.05, # aumenta pra achar mais e diminui pra achar menos minDistance=30) # distancia entre pontos parameters_lucas_kanade = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.05)) colors = np.random.randint(0, 255, (100, 3)) ret, frame = cap.read() frame_gray_init = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) edges = cv2.goodFeaturesToTrack(frame_gray_init, mask=None, **parameters_shitomasi) mask = np.zeros_like(frame) # print(edges) #localização dos pontos inicias marcados # print(len(edges)) # contagem de pontos indentificados # print(mask) # print(np.shape(mask)) #dimensão do vídeo while (cap.isOpened): ok, frame = cap.read() if not ok: print("ERRO...") break bg_mask = bg_subtractor.apply(frame) fg_mask = getFilter(bg_mask, 'combine') result = cv2.bitwise_and(frame, frame, mask=fg_mask) frame_gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY) new_edges, status, errors = cv2.calcOpticalFlowPyrLK(frame_gray_init, frame_gray, edges, None, **parameters_lucas_kanade) news = new_edges[status == 1] olds = edges[status == 1] for i, (new, old) in enumerate(zip(news, olds)): a, b = new.ravel() c, d = old.ravel() # Não entendi esta parte # a, b, c, d = int(a), int(b), int(c), int(d) mask = cv2.line(mask, (a, b), (c, d), colors[i].tolist(), 2) frame = cv2.circle(result, (a, b), 5, colors[i].tolist(), -1) img = cv2.add(result, mask) cv2.imshow('BGS + Optical flow', img) if cv2.waitKey(1) == 13: break frame_gray_init = frame_gray.copy() edges = news.reshape(-1, 1, 2) # Acionamento do main() SK()
13 de março de 2022 às 09:46 #33717Olá Dalton, vi seu vídeo e de fato está rodando, mas no meu vídeo teste eu não consigo rodar esse código, fico com o mesmo erro que mandei anteriormente. Vou mandar meu vídeo para ver se você consegue encontrar o problema, o algoritmo é o mesmo que você mandou.
https://drive.google.com/file/d/1WXv7sMaxNtVae3rQkQfoc4gn7amuIFGR/view?usp=sharing
Ah, e a linha que eu passo as variáveis para inteiros foi só uma passagem porque anteriormente estava dando erro também, acho que para o vídeo que estou usando existem alguns problemas e não tô sabendo resolver. Vou mandar o Erro de novo também.
Traceback (most recent call last):
File “C:\Users\Pedro Henrique\PycharmProjects\IC\teste1.py”, line 131, in <module>
SK()
File “C:\Users\Pedro Henrique\PycharmProjects\IC\teste1.py”, line 107, in SK
news = new_edges[status == 1]
TypeError: ‘NoneType’ object is not subscriptableProcess finished with exit code 1
21 de março de 2022 às 07:35 #33814Olá Pedro!
Fiz o teste aplicando somente o Optical Flow e parece que devido aos insetos estarem desfocados desde o início do vídeo, o algoritmo não consegue indetificar os contornos/arestas. Já nos objetos que estão mais nítidos (marca da câmera, tempo de vídeo, camisa branca ao fundo) ele consegue identificar. Segue o vídeo .
Minha sugestão seria gravar um vídeo mais focado nos insetos (se estes forem o objetivo).
Também se puder compartilhar a ideia do projeto, assim podemos pensar em mais soluções. Caso não queira compartilhar aqui no fórum, pode mandar no meu e-mail: daltonluizvargas@hotmail.com
- Esta resposta foi modificada 2 anos, 12 meses atrás por
Dalton Vargas.
- Esta resposta foi modificada 3 anos atrás por
- AutorPosts
- Você deve fazer login para responder a este tópico.