Je veux faire du masquage logique dans Julia.
Si les 2e et 3e éléments d'une image sont égaux, ils doivent être remplacés par 0 et les autres ne doivent pas l'être.
J'ai essayé ceci;

mask = img[:, :, 2] .== img[:, :, 3]
img[:, :, 2][mask] .= 0

La taille de l'image est (1200, 1920, 3), mais la taille de l'image [:,:, 2] est (1676348,).
Je suppose que les valeurs «vraies» sur le masque restent, mais les valeurs «fausses» sont supprimées.
Je veux traiter l'image logiquement masquée comme une image, elle devrait donc être (1200, 1920, 1).
Comment conserver la taille avec un masquage logique?

2
Kotaro Nomura 27 oct. 2020 à 09:13

2 réponses

Meilleure réponse

La meilleure façon d'écrire ce que vous demandez pourrait être img[mask, 2] .= 0, mais cela ne fonctionne pas sur Julia jusqu'à 1.5. Pour contourner ce problème, vous pouvez créer une tranche mutable avec @view:

julia> img = cat([1 2; 3 4], [1 5; 6 7]; dims=3)
2×2×2 Array{Int64, 3}:
[:, :, 1] =
 1  2
 3  4

[:, :, 2] =
 1  5
 6  7

julia> mask = img[:,:,1] .== img[:,:,2]
2×2 BitMatrix:
 1  0
 0  0

julia> v = @view img[:,:,2]
2×2 view(::Array{Int64, 3}, :, :, 2) with eltype Int64:
 1  5
 6  7

julia> v[mask] .= 0
1-element view(reshape(view(::Array{Int64, 3}, :, :, 2), 4), [1]) with eltype Int64:
 0

julia> img
2×2×2 Array{Int64, 3}:
[:, :, 1] =
 1  2
 3  4

[:, :, 2] =
 0  5
 6  7

Il convient de souligner que sans @view, v = img[:,:,2] créerait une copie de cette tranche de img, et par conséquent toutes les modifications que vous avez apportées à v ne serait pas reflété dans img. La vue garantit que v reste couplé à img.

La taille de l'image est (1200, 1920, 3), mais la taille de l'image [:,:, 2] est (1676348,).

Pour plus de précision, je dois souligner que ce n'est pas vrai. Utilisation de img ci-dessus:

julia> size(img[:,:,2])
(2, 2)
1
tholy 27 oct. 2020 à 10:54

Éditer:

Le moyen le plus rapide de le faire est:

@views @. img[:, :, 2] *= img[:, :, 2] != img[:, :, 3]

Et voici un benchmark:

julia> img = rand(1:3, 10000, 10000, 3);

julia> @time @views @. img[:, :, 2] *= img[:, :, 2] != img[:, :, 3];
  0.111409 seconds (28 allocations: 1.219 KiB)

Il existe d'autres moyens de faire ce que vous voulez, mais si nous voulons suivre votre implémentation, procédez comme suit:

julia> img = rand(1:3, 4,4,3)
4×4×3 Array{Int64,3}:
[:, :, 1] =
 1  3  2  3
 1  1  1  3
 3  2  1  3
 2  2  3  1

[:, :, 2] =
 1  2  3  2
 2  2  1  1
 3  3  3  2
 1  3  2  1

[:, :, 3] =
 3  2  2  2
 3  2  2  1
 3  2  3  3
 2  2  1  2

julia> mask = img[:, :, 2] .== img[:, :, 3]
4×4 BitArray{2}:
 0  1  0  1
 0  1  0  1
 1  0  1  0
 0  0  0  0

julia> view(img,:, :, 2)[mask] .= 0;

julia> img
4×4×3 Array{Int64,3}:
[:, :, 1] =
 1  3  2  3
 1  1  1  3
 3  2  1  3
 2  2  3  1

[:, :, 2] =
 1  0  3  0
 2  0  1  0
 0  3  0  2
 1  3  2  1

[:, :, 3] =
 3  2  2  2
 3  2  2  1
 3  2  3  3
 2  2  1  2

(il est crucial d'utiliser view pour obtenir ce que vous voulez, sinon img[:, :, 2] crée une copie)

Alternativement, dans Julia, il est assez facile d'écrire la même chose en utilisant la boucle, par exemple:

function applymask!(img)
    for i in axes(img, 1), j in axes(img, 2)
        img[i, j, 2] == img[i, j, 3] && (img[i, j, 2] = 0)
    end
end

(ce n'est pas l'implémentation la plus rapide possible car elle utilise le branchement et vérifie les limites, mais elle devrait être suffisante dans la plupart des cas)

Et maintenant vous pouvez écrire:

julia> img = rand(1:3, 4,4,3)
4×4×3 Array{Int64,3}:
[:, :, 1] =
 1  3  1  3
 3  3  1  2
 3  3  3  3
 2  1  3  1

[:, :, 2] =
 3  1  3  1
 3  3  3  3
 2  1  1  3
 1  2  3  3

[:, :, 3] =
 1  1  2  1
 2  1  3  2
 3  3  1  1
 1  2  1  3

julia> applymask!(img)

julia> img
4×4×3 Array{Int64,3}:
[:, :, 1] =
 1  3  1  3
 3  3  1  2
 3  3  3  3
 2  1  3  1

[:, :, 2] =
 3  0  3  0
 3  3  0  3
 2  1  0  3
 0  0  3  0

[:, :, 3] =
 1  1  2  1
 2  1  3  2
 3  3  1  1
 1  2  1  3
3
Bogumił Kamiński 27 oct. 2020 à 12:01