Commit e9720d21 authored by Diego André Sant'Ana's avatar Diego André Sant'Ana 🤞
Browse files

Melhoria de desempenho do arquivo do Extrator de Atributos. Adicionado novo...

Melhoria de desempenho do arquivo do Extrator de Atributos. Adicionado novo extrator chamado KCurvature, responsável por extrair a quantidade de angulos de uma imagem por faixas. Adicionado a funcionalide de extrair frames de videos.
parent dba33431
......@@ -18,4 +18,4 @@ statistics
pandas_ml
pyxdg
opencv-contrib-python
python-interface
......@@ -6,6 +6,8 @@ from .hog import HOG
from .image_moments import RawCentralMoments, HuMoments
from .lbp import LBP
from .gabor import GABOR
from .kcurvature import KCURVATURE
__all__ = ["extractor",
"color_summarizer",
......@@ -13,7 +15,8 @@ __all__ = ["extractor",
"hog",
"image_moments",
"lbp",
"gabor"]
"gabor",
"kcurvature"]
from collections import OrderedDict
......@@ -27,7 +30,8 @@ _extractor_list = OrderedDict( [
["hu_moments", Config("Hu Image Moments", True, bool, meta=HuMoments)],
["rc_moments", Config("Image Moments (Raw/Central)", True, bool, meta=RawCentralMoments)],
["lbp", Config("Local Binary Patterns", True, bool, meta=LBP)],
["gabor", Config("Gabor Filter Bank", True, bool, meta=GABOR)]
["gabor", Config("Gabor Filter Bank", True, bool, meta=GABOR)],
["kcurvature", Config("K-Curvature Angles", True, bool, meta=KCURVATURE)]
] )
def get_extractor_config():
......@@ -41,3 +45,4 @@ def set_extractor_config(configs):
_extractor_list["rc_moments"] = Config.nvl_config(configs["rc_moments"], _extractor_list["rc_moments"])
_extractor_list["lbp"] = Config.nvl_config(configs["lbp"], _extractor_list["lbp"])
_extractor_list["gabor"] = Config.nvl_config(configs["gabor"], _extractor_list["gabor"])
_extractor_list["kcurvature"] = Config.nvl_config(configs["kcurvature"], _extractor_list["kcurvature"])
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Extract frames from video
Selecter folder where stay videos, before select folder where extract frames.
Name: extractor_frame_movie.py
Author: Diego Andre Sant Ana ( diego.santana@ifms.edu.br )
"""
import os
from os import listdir
from os.path import isfile, join
import cv2
import threading
import tkFileDialog
from Tkinter import *
from util.utils import TimeUtils
class ExtractFM(object):
def __init__(self):
pass
def run(self,tk):
self.tk=tk
self.folder_a=None
self.folder_b=None
#janela
self.window = Tk()
self.window.title("Extract Frames from videos")
self.window.attributes('-zoomed', False)
self.window.geometry("450x250+300+300")
self.frame = Frame(self.window )
self.frame.pack(fill=X, expand=False)
self.folder_source = Button(self.frame, text="Select Folder Source", padx=5, pady=5, command = self.select_folder_source)
self.folder_source.pack(padx=5, pady=5, expand=True, fill=X)
self.label_a =Label(self.frame, text="Folder no selected", padx=5, pady=5)
self.label_a.pack(padx=5, pady=5, expand=True, fill=X)
self.folder_export = Button(self.frame, text="Select Folder Source", padx=5, pady=5, command = self.select_folder_export)
self.folder_export.pack(padx=5, pady=5, expand=True, fill=X)
self.label_b =Label(self.frame, text="Folder no selected", padx=5, pady=5)
self.label_b.pack(padx=5, pady=5, expand=True, fill=X)
self.buttonOpen = Button(self.frame, text="Run Extract", padx=5, pady=5, command = self.export_frame)
self.buttonOpen.pack(padx=5, pady=5, expand=True, fill=X)
# Open the GUI
self.window.mainloop()
def extract_frame(self, file,caminho):
newDir= self.folder_b+"/"+file.replace(file.split(".")[-1] ,"")
try:
print("Create Folder:"+newDir)
os.mkdir(newDir)
except OSError:
print("Folder exists:"+newDir)
cap = cv2.VideoCapture(caminho)
counter_frame = 0;
while(counter_frame<500000):
print(counter_frame)
ret, img= cap.read()
if(ret == False):
return
cv2.imwrite((newDir+"/"+str(counter_frame)+".png").encode('utf-8').strip(), img)
counter_frame+=1
cap.release()
def export_frame(self):
if self.folder_a is None:
return
if self.folder_b is None:
return
#dir='../dataset_20180816/'
dir=self.folder_a
listaArquivo = [f for f in listdir(dir) if isfile(join(dir, f))]
self.tk.append_log("Init process:"+ str(listaArquivo))
lista_thread=[]
start_time = TimeUtils.get_time()
for r, d, f in os.walk(dir):
for file in f:
ext=file.split(".")[-1]
if ext =="avi" or "mp4"==ext :
t=threading.Thread(target=self.extract_frame,args=(file, os.path.join(r, file)))
t.start()
lista_thread.append(t)
self.tk.append_log("Threads running:"+str(threading.activeCount()))
for t in (lista_thread):
t.join()
end_time = TimeUtils.get_time()
self.tk.append_log("Finish process:"+str(end_time - start_time))
def select_folder_source(self):
self.folder_a=None
options = {
'title': 'Auto select all videos from folder(AVI or MP4)',
'filetypes': (("File MP4", '*.mp4'), ('File AVI', '*.avi'))
}
filename = tkFileDialog.askdirectory()
if(filename != ''):
self.folder_a = filename
self.label_a.configure(text=self.folder_a )
self.window.update_idletasks()
def select_folder_export(self):
self.folder_b=None
options = {
'title': 'Select folder to export frames(PNG)',
'filetypes': (('File PNG', '*.png'))
}
filename = tkFileDialog.askdirectory()#askopenfilename(**options)
if(filename != ''):
self.folder_b = filename
self.label_b.configure(text=self.folder_b )
self.window.update_idletasks()
#tela=ExtractFM().run()
......@@ -12,13 +12,16 @@ import io
import itertools
import os
import threading
from interface.interface import InterfaceException as IException
from util.file_utils import File
from util.utils import ImageUtils
from util.utils import TimeUtils
import cv2
from extractor import Extractor
import sys
class FeatureExtractor(object):
"""Handle the feature extraction."""
......@@ -33,15 +36,14 @@ class FeatureExtractor(object):
"""
self.extractors = extractors
def extract_all(self, dataset, output_file=None, dirs=None, overwrite=True):
self.labels = []
self.types = []
def extract_all(self, dataset, output_file = None, dirs = None, overwrite = True):
self.labels=[]
self.types=[]
self.data=[]
self.threads=[]
self.labels=[]
self.types=[]
self.data = []
self.threads = []
self.labels = []
self.types = []
"""Runs the feature extraction algorithms on all images of dataset.
Parameters
......@@ -85,57 +87,65 @@ class FeatureExtractor(object):
classes = sorted(File.list_dirs(dataset))
dirs = classes if dirs is None else dirs
# Runs the feature extraction for all classes inside the dataset
for cl in dirs:
for i,cl in enumerate(dirs):
# start job for each extractor
process = threading.Thread(target=self.job_extractor, args=[ dataset, cl, classes ])
process.start()
self.threads.append(process)
#wait jobs finish
for process in self.threads:
process.join()
th = threading.Thread(target=self.job_extractor,args=(dataset, cl, classes))
th.start()
self.threads.append(th)
for t in self.threads:
t.join()
if len(self.data) == 0:
raise IException("There are no images in dataset: %s" % dataset)
# Save the output file in ARFF format
# self._save_output(File.get_filename(dataset), classes, self.labels, self.types, self.data, output_file)
self._save_output(File.get_filename(dataset), classes, self.labels, self.types, self.data, output_file)
end_time = TimeUtils.get_time()
return output_file, (end_time - start_time)
def job_extractor(self,dataset, cl, classes ):
# create one thread for folder
def job_extractor(self, dataset, cl, classes):
items = sorted(os.listdir( File.make_path(dataset, cl)))
items = sorted(os.listdir(File.make_path(dataset, cl)))
print("Processing class %s - %d itens" % (cl, len(items)))
for item in items:
values=[]
if item.startswith('.'):
continue
try:
filepath = File.make_path(dataset, cl, item)
image = File.open_image(filepath, rgb = False )
except:
raise IException("Image %s is possibly corrupt" % filepath)
if len(self.data) > 0:
values = list(itertools.chain.from_iterable(zip(*([extractor().run(image) for extractor in self.extractors]))[2] ))
self.data.append(values + [cl if cl in classes else classes[0]])
else:
self.labels, self.types, values = [ list(itertools.chain.from_iterable(ret))
for ret in zip(*([extractor().run(image) for extractor in self.extractors])) ]
self.data.append(values + [cl if cl in classes else classes[0]])
def extract_one_file(self, dataset, image_path, output_file = None):
for item in items :
if item.startswith('.'):
continue
th = threading.Thread(target=self.sub_job_extractor,args=(item, dataset, cl, classes))
th .start()
self.threads.append(th)
# create one thread each image for use extractor
def sub_job_extractor(self, item, dataset, cl, classes):
try:
filepath = File.make_path(dataset, cl, item)
image = cv2.imread(filepath)
#image = self.equalize_size_image(image)
except:
raise IException("Image %s is possibly corrupt" % filepath)
if len(self.data) > 0:
values = list(
itertools.chain.from_iterable(zip(*([extractor().run(image) for extractor in self.extractors]))[2]))
self.data.append(values + [cl if cl in classes else classes[0]])
else:
self.labels, self.types, values = [list(itertools.chain.from_iterable(ret))
for ret in
zip(*(extractor().run(image) for extractor in self.extractors))]
self.data.append(values + [cl if cl in classes else classes[0]])
def extract_one_file(self, dataset, image_path, output_file=None):
"""Runs the feature extraction algorithms on specific image.
Parameters
----------
dataset : string
......@@ -144,12 +154,12 @@ class FeatureExtractor(object):
Path to image.
output_file : string, optional, default = None
Name of output file continaing the features. If not informed is considered the name of dataset.
Returns
-------
out : tuple
out : tuple
Returns a tuple containing the name of output file and time spent in milliseconds.
Raises
------
IException 'Please select at least one extractor'
......@@ -159,30 +169,29 @@ class FeatureExtractor(object):
"""
if len(self.extractors) == 0:
raise IException("Please select at least one extractor")
if output_file is None:
output_file = File.get_filename(dataset)
output_file = File.make_path(dataset, output_file + '.arff')
classes = sorted(File.list_dirs(dataset))
start_time = TimeUtils.get_time()
try:
image = File.open_image(image_path, rgb = False )
image = File.open_image(image_path, rgb=False)
except:
raise IException("Image %s is possibly corrupt" % filepath)
labels, types, values = [ list(itertools.chain.from_iterable(ret))
for ret in zip(*([extractor().run(image) for extractor in self.extractors])) ]
labels, types, values = [list(itertools.chain.from_iterable(ret))
for ret in zip(*([extractor().run(image) for extractor in self.extractors]))]
self._save_output(File.get_filename(dataset), classes, labels, types, [values + [classes[0]]], output_file)
end_time = TimeUtils.get_time()
return output_file, (end_time - start_time)
def _save_output(self, relation, classes, labels, types, data, output_file):
"""Save output file in ARFF format.
......@@ -201,21 +210,45 @@ class FeatureExtractor(object):
output_file : string
Path to output file.
"""
arff = open(output_file,'wb')
arff = open(output_file, 'wb')
arff.write("%s %s\n\n" % ('@relation', relation))
for label, t in zip(labels, types):
arff.write("%s %s %s\n" % ('@attribute', label, t))
arff.write("%s %s {%s}\n\n" % ('@attribute','classe',', '.join(classes)))
arff.write("%s %s {%s}\n\n" % ('@attribute', 'classe', ', '.join(classes)))
arff.write('@data\n\n')
for instance in data:
instance = map(str, instance)
line = ",".join(instance)
arff.write(line+"\n")
arff.write(line + "\n")
arff.close()
#method to equalize size of images
def equalize_size_image(self, image):
if (image.shape[0] > 1000):
basewidth = 1000
wpercent = (basewidth / float(image.shape[0] ))
hsize = int((float(image.shape[1] ) * float(wpercent)))
image = cv2.resize(image, (basewidth, hsize))
elif (image.shape[1] > 1000):
baseheight = 1000
wpercent = (baseheight / float(image.shape[1] ))
wsize = int((float(image.shape[1] ) * float(wpercent)))
image = cv2.resize(image, (wsize, baseheight))
elif (image.shape[1] <1000):
baseheight = 1000
wpercent = (baseheight / float(image.shape[1] ))
wsize = int((float(image.shape[1] ) * float(wpercent)))
image = cv2.resize(image, (wsize, baseheight))
elif (image.shape[0] < 1000):
basewidth = 1000
wpercent = (basewidth / float(image.shape[0] ))
hsize = int((float(image.shape[1] ) * float(wpercent)))
image = cv2.resize(image, (basewidth, hsize))
return image
......@@ -22,6 +22,7 @@ from skimage import feature
from skimage.filters import gabor_kernel
from skimage.util import img_as_float
import torch
class GABOR(Extractor):
......@@ -45,7 +46,7 @@ class GABOR(Extractor):
features : tuple
Returns a tuple containing a list of labels, type and values for each feature extracted.
"""
#deprecaded
def compute_feats(image, kernels):
feats = np.zeros((len(kernels), 2), dtype=np.double)
for k, kernel in enumerate(kernels):
......@@ -57,14 +58,13 @@ class GABOR(Extractor):
values.append(feats[k, 1])
return feats
#deprecaded
def power(image, kernel):
image = (image - image.mean()) / image.std()
return np.sqrt(ndi.convolve(image, np.real(kernel), mode='wrap')**2 +
ndi.convolve(image, np.imag(kernel), mode='wrap')**2)
image_grayscale = ImageUtils.image_grayscale(image, bgr = True)
image_float = img_as_float(image_grayscale)
......@@ -78,15 +78,20 @@ class GABOR(Extractor):
theta = theta / 8. * np.pi
for sigma in (1, 3):
for frequency in (0.01, 0.10, 0.25, 0.5,0.9):
kernel = np.real(gabor_kernel(frequency, theta=theta,
sigma_x=sigma, sigma_y=sigma))
kernels.append(kernel)
print ("Thet_%f_Sigma_%i_Frequencia_%.2f" % (theta, sigma, frequency))
kernel = np.real(gabor_kernel(frequency, theta=theta, sigma_x=sigma, sigma_y=sigma))
#kernels.append(kernel)
filtered = ndi.convolve(image_float, kernel, mode='wrap')
import time
values.append(filtered.mean())
values.append(filtered.var())
#print ("Thet_%f_Sigma_%i_Frequencia_%.2f" % (theta, sigma, frequency))
for stat in ("Mean", "Variance"):
labels.append("Thet_%f_Sigma_%i_Frequencia_%.2f_%s" % (theta, sigma, frequency, stat))
compute_feats(image_float,kernels)
#compute_feats(image_float,kernels)
types = ['numeric'] * len(labels)
......
"""
Baseado no algoritmo abaixo
https://github.com/accord-net/framework/blob/a5a2ea8b59173dd4e695da8017ba06bc45fc6b51/Sources/Accord.Math/Geometry/KCurvature.cs"""
import numpy as np
import math
from extractor import Extractor
import sys
import cv2
import matplotlib.pyplot as plt
from skimage import feature
class KCURVATURE(Extractor):
"5,30, [0,180]"
def __init__(self):
#__init__(self, k, band, theta):
self.k =35
self.theta = [0,180]
self.band=20
self.suppression = self.k
pass
def angle_abc(self, a, b, c ):
ab = [ b[0] - a[0], b[1] - a[1] ]
cb = [ b[0] - c[0], b[1] - c[1] ]
# dot product
dot = (ab[0] * cb[0] + ab[1] * cb[1])
cross = (ab[0] * cb[1] - ab[1] * cb[0])
alpha = np.math.atan2(cross, dot)
return int( np.math.floor(alpha * 180. / math.pi + 0.5))
def find_angle(self,contours, image):
list_angle=[]
j=0
for contour in contours:
t=len(contour)
map=[t]
for i, con in enumerate(contour):
#im=np.copy(image)
ai = (i + self.k) % t
ci = (i - self.k) % t
aX=contour[ai][0][0]
aY=contour[ai][0][1]
bX=contour[i][0][0]
bY=contour[i][0][1]
cX = contour[ci][0][0]
cY = contour[ci][0][1]
list_angle.append(self.angle_abc([aX,aY],[bX,bY],[cX,cY]))
"""test plot line and angle
pts = np.array([[aX,aY],[bX,bY],[cX,cY]], np.int32)
pts = pts.reshape((-1,1,2))
cv2.polylines(im,[pts],True,(255,0,255))
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(im,'Angle:'+str(list_angle[i]),(bX,bY+8), font, 1,(255,0,255),1,cv2.LINE_AA)
cv2.imwrite("../../data/demo/teste/"+str(t)+"_" +str( j)+".png", im)
j=j+1
"""
return list_angle,image
""""https://dsp.stackexchange.com/questions/37281/improving-canny-edge-detection-and-contours-image-segmentation"""
def auto_canny(self,image, sigma=0.5):
v = np.median(image)
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
return cv2.Canny(image, lower, upper)
def run(self, image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 9)
ret,gray = cv2.threshold( np.copy(gray),127,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C/cv2.THRESH_BINARY_INV)
#ret,gray = cv2.threshold( np.copy(gray),127,255,)
#kernel = np.ones((5,5),np.uint8)
#gray=cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
#gray = cv2.dilate(gray,kernel,iterations = 1)
#gray = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)
#binario
#ret, thresh = cv2.threshold(np.copy(gray), 127, 255, 0)
edges = self.auto_canny(gray, 1)
img2,contours,hierarchy = cv2.findContours(edges ,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#print(contours)
list,image=self.find_angle(contours,img2)
labels = []
values = []
list_band=[]
for i in range(180/self.band):
list_band.append(0)
for j,angle in enumerate(list):
angle = abs(angle)
#print(angle)
if(angle>=i*self.band and angle<((i+1)*self.band)):
list_band[i]=list_band[i]+1
elif (180==angle and 180/self.band==i):
list_band[i]=list_band[i]+1
for i, c in enumerate(list_band):
if(180==(i+1)*self.band):
labels.append("K_%i_%i" % (i*self.band,180))
else:
labels.append("K_%i_%i" % (i*self.band,(i+1)*self.band-1))