Fitopatometria

Diretório das imagens

# mudar de acordo com a pasta em seu computador
setwd("E:/Desktop/tiagoolivoto/static/tutorials/pliman_esalq/leaves")

Severidade da doença

Utilizando paletas

# gerar tabelas html
print_tbl <- function(table,  digits = 3, ...){
  knitr::kable(table, booktabs = TRUE, digits = digits, ...)
}
library(pliman)
## |=======================================================|
## | Tools for Plant Image Analysis (pliman 0.3.0)         |
## | Author: Tiago Olivoto                                 |
## | Type 'vignette('pliman_start')' for a short tutorial  |
## | Visit 'https://bit.ly/pliman' for a complete tutorial |
## |=======================================================|
img <- image_import("img_1.jpeg")
h <- image_import("h_img1.png")
d <- image_import("d_img1.png")
b <- image_import("b_img1.png")
image_combine(img, h, d, b, ncol = 4)

Padrão da função

sev <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE)

##   healthy symptomatic
##  76.32428    23.67572

Mostrando preenchimento das lesões

sev <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  show_contour = FALSE)

##   healthy symptomatic
##  75.52765    24.47235

Mostrando uma máscara

sev <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  show_contour = FALSE,
                  show_original = FALSE)

##   healthy symptomatic
##  75.71474    24.28526

Segmentando as lesões

sev <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  show_contour = FALSE, # não mostra os contornos
                  segment = TRUE, # segmenta as lesões que se tocam por poucos pixeis
                  show_segmentation = TRUE) # mostra as segmentações

##   healthy symptomatic
##  76.66014    23.33986

Analisar as lesões

feat <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  segment = TRUE,
                  show_features = TRUE, # computa características das lesões
                  lesion_size = "medium") # padrão

##   healthy symptomatic
##  76.08522    23.91478
print_tbl(feat$statistics)
stat value
n 424.000
min_area 35.000
mean_area 429.205
max_area 6644.000
sd_area 577.445
sum_area 181983.000
print_tbl(feat$shape[1:10, ])
id x y area perimeter radius_mean radius_min radius_max radius_sd radius_ratio major_axis eccentricity theta
1 1060.298 274.790 6644 399 46.650 19.960 71.955 11.549 3.605 118.041 0.683 -0.047
2 1058.626 361.842 5354 362 40.750 25.442 53.924 6.355 2.119 89.904 0.420 -1.512
3 463.372 536.354 6297 432 45.609 27.939 61.951 8.971 2.217 115.499 0.765 -0.083
4 635.068 690.510 2892 290 30.920 15.833 45.253 6.987 2.858 73.518 0.600 1.256
5 773.982 402.086 1768 163 23.417 18.567 30.553 2.941 1.646 54.829 0.637 1.081
6 800.030 317.214 2856 271 30.672 14.397 43.828 7.355 3.044 82.335 0.799 0.738
7 1123.307 352.000 2004 211 25.378 15.157 35.924 4.673 2.370 61.036 0.668 -0.601
8 331.393 535.152 1187 140 19.208 12.609 24.671 2.776 1.957 45.128 0.626 -1.537
9 1109.321 496.102 957 114 17.169 13.063 22.222 2.110 1.701 38.183 0.479 -0.586
10 1091.068 470.443 1299 154 20.077 11.530 26.759 3.733 2.321 47.547 0.577 -1.130
# corrigir as medidas (dpi = 150)
feat_corrected <- get_measures(feat, dpi = 150)
feat <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  segment = TRUE,
                  show_features = TRUE, # computa características das lesões
                  lesion_size = "large") 

##   healthy symptomatic
##  75.93441    24.06559

O valor de tolerance define a tolerancia para segmentação de objetos que se encostam. Menores valores tendem a dividir objetos mais facilmente.

feat <- 
  measure_disease(img = img,
                  img_healthy = h,
                  img_symptoms = d,
                  img_background = b,
                  show_image = TRUE,
                  segment = TRUE,
                  tolerance  = 0.2) 

##   healthy symptomatic
##  76.12413    23.87587

A little bit more!

# library(pliman)
sev_img2 <- 
  measure_disease(img = "img_2",
                  img_healthy = "h_img2",
                  img_symptoms = "d_img2",
                  img_background = "b_img2",
                  show_image = FALSE,
                  show_contour = FALSE,
                  col_background  = "black")
##   healthy symptomatic
##  91.58738    8.412622
imgs <- image_import(c("img_2.jpeg", "mask_im2.jpeg"))
image_combine(imgs)

Mais de uma folha

sev_folhas <- 
  measure_disease(img = "soy_21",
                  img_healthy = "h_s",
                  img_symptoms = "d_s",
                  img_background = "b_s",
                  show_image = TRUE,
                  save_image = TRUE,
                  show_contour = FALSE,
                  col_background = "black")

##   healthy symptomatic
##  70.15104    29.84896

Utilizando índices RGB

Para identificar o melhor índice para segmentar a imagem do fundo e após as lesões da folha sadia, pode-se utilizar a função image_segment_iter. (OBS. somente funcionará em uma seção iterativa).

image_segment_iter(img)

Após escolhidos os índices, podemos utilizar os argumentos index_lb e index_dh para segmentação da folha e fundo | lesão e sadio, respectivamente.

# após escolhidos os índices, utiliza
sev_index <- 
  measure_disease(img, 
                  index_lb = "G",
                  index_dh = "NGRDI",
                  show_image = TRUE)

##   healthy symptomatic
##  74.34505    25.65495

Processamento em lote

Para analisar diversas imagens de um diretório, utiliza-se o argumento pattern, para declarar um padrão de nomes de arquivos. Serão utilizadas 15 folhas de soja disponíveis no repositório https://osf.io/4hbr6, um banco de dados de imagens de anotação de severidade de doenças de plantas. Obrigado a Emerson M. Del Ponte e seus colaboradores por manter este projeto disponível publicamente.

system.time(
  sev_lote <- 
    measure_disease(pattern = "soy",
                    img_healthy = "h_s",
                    img_symptoms = "d_s",
                    img_background = "b_s",
                    verbose = FALSE)
)
##   usuário   sistema decorrido 
##     15.05      0.97     16.14
print_tbl(sev_lote$severity)
img healthy symptomatic
proc_soy_21 56.096 43.904
soy_1 92.473 7.527
soy_10 84.729 15.271
soy_11 15.779 84.221
soy_12 64.419 35.581
soy_13 78.416 21.584
soy_14 61.373 38.627
soy_15 60.489 39.511
soy_16 41.573 58.427
soy_17 78.194 21.806
soy_18 54.525 45.475
soy_19 87.727 12.273
soy_2 62.120 37.880
soy_20 51.608 48.392
soy_21 70.733 29.267
soy_3 59.113 40.887
soy_4 44.320 55.680
soy_5 83.497 16.503
soy_6 73.264 26.736
soy_7 76.791 23.209
soy_8 70.425 29.575
soy_9 57.430 42.570
# exporta os resultados
# rio::export(sev_lote$severity, "severidade.xlsx")

Para acelerar o tempo de processamento quando várias imagens estão disponíveis, pode-se utilizar o argumento paralell. Isto criará múltiplas seções R em segundo plano, sendo cada uma responsável pelo processamento de uma parte das imagens.

system.time(
  sev_lote <- 
    measure_disease(pattern = "soy",
                    img_healthy = "h_s",
                    img_symptoms = "d_s",
                    img_background = "b_s",
                    verbose = FALSE,
                    parallel = TRUE)
)
##   usuário   sistema decorrido 
##      0.22      0.03     10.17

Desafios

Lesões com pouco contraste

pepper <- image_import("pepper.png", plot = TRUE)

image_index(pepper, index = "all")

Fundos complexos

img <- image_import("maize_1.png", plot = TRUE)

image_segment(img, index = "all")

img <- image_import("maize_2.png", plot = TRUE)

image_segment(img, index = "all")

img2 <- image_crop(img,
                   width = 959:32,
                   height = 163:557,
                   plot = TRUE)


image_segment_iter(img2, 
                   nseg = 2, # define o número de segmentações
                   index = c("R/(G+B)", "GLI"), # índices para primeira e segunda
                   invert = c(T, F), # inverter a segmentação? (passa um vetor)
                   ncol = 3) # número de colunas no plot
##      image  pixels   percent
## 1 original 1466240 100.00000
## 2     seg1   72072   4.91543
## 3     seg2   17214  23.88445

img <- image_import("maize_3.png", plot = TRUE)

image_segment(img, index = "all")

Previous