6
$\begingroup$

I have a list of pictures:

pictures = {im1,im2,im3,im4,im5,im6}

Where

im1: enter image description here

im2: enter image description here

im3: enter image description here

im4: enter image description here

im5: enter image description here

im6: enter image description here

I want to assign the pictures to labels (1,2,3,4,5 etc.). The pictures are already ordered according to their label. What I still need to do is to define the range of the labels.

For instance, here pictures 1 to 3 belong to label 1, picture 4 belongs to label 2, picture 5 to label 3, and picture 6 to label 4.

-> label = {1,1,1,2,3,4}

Since I need to see the images when I label them, I need a method to do that while labeling them. I was thinking of creating an array of images:

enter image description here

And then I define the ranges by clicking on the first and last picture belonging to the same labels, so for example:

enter image description here

What do you think ? Is this somehow possible ?

EDIT: Thank you all very much for the great answers. However, I think that I might have been not clear enough with the description of my question: I would like to assign different labels to different ranges of pictures.

enter image description here

For instance: When one has finished selecting the first label one could indicate it by a Double-click and then do the selection of the second label range, then Double-click, then do the selection of the third label range, then Double-click, then do the selection of the fourth label range, etc.

It does not have to be Double-clicking to change the selection of the labels, it could also just be a buttom or any other idea that you might have.

In the end one should have the list of labels.

EDIT: This is what I have implemented so far (using the accepted answer):

m = 1;
n = 20;
i = 0;
labels = {};
{beginSelect, endSelect} = {0, 0};

selectImage[id_] := 
 If[beginSelect == 0, beginSelect = id, 
  endSelect = Max[beginSelect, id]]

makeImage[img_, False] := 
 Show[ImagePad[img, 5, White], ImageSize -> 100]
makeImage[img_, True] := Show[ImagePad[img, 5, Red], ImageSize -> 100]

addEventHandler[img_, id_] := 
 EventHandler[
  MouseAppearance[img, 
   "LinkHand"], {"MouseClicked" :> selectImage[id]}]

displayImages[imgs_] := 
 Grid[Partition[
   MapThread[
    addEventHandler[
      makeImage[#, 
       beginSelect <= #2 && #2 <= endSelect], #2] &, {imgs, 
     Range@Length@imgs}], 5]]


Dynamic[Deploy@Column[{displayImages[imgs[[m ;; n]]],
    Button["Next", If[m <= Length[imgs], {n = n + 5, m = m + 5}]],
    Button["New Label", 
     AppendTo[labels, i -> Range[beginSelect, endSelect]]; i++; 
     beginSelect = 0; endSelect = 0 ],
    Button["Back", If[n - 5 >= 1, {n = n - 5, m = m - 5} ]]}], 
 TrackedSymbols :> {beginSelect, endSelect, m, n}]

UPDATE 2:

Dynamic[Deploy@Column[{displayImages[imgs[[m ;; n]]],
    Button["Next", 
     If[m <= Length[imgs], {n = n + 5, m = m + 5}; 
      beginSelect = beginSelect - 5; endSelect = endSelect - 5]],
    Button["New Label", 
     AppendTo[labels, Table[i, {j, 1, (endSelect - beginSelect)}]]; 
     i++; beginSelect = endSelect + 1; endSelect = endSelect + 2],
    Button["Back", If[n - 5 >= 1, {n = n - 5, m = m - 5} ]]}], 
 TrackedSymbols :> {beginSelect, endSelect, m, n}]
$\endgroup$
1
$\begingroup$

Here's another version:

imgs = Flatten@ConstantArray[ConformImages[{
      Import["https://i.stack.imgur.com/cML6z.jpg"],
      Import["https://i.stack.imgur.com/6EVAP.jpg"],
      Import["https://i.stack.imgur.com/CAxUw.jpg"],
      Import["https://i.stack.imgur.com/8fhan.jpg"],
      Import["https://i.stack.imgur.com/eMXn5.jpg"],
      Import["https://i.stack.imgur.com/YFBfM.jpg"]
      }], 2];

{beginSelect, endSelect} = {0, 0};
selectImage[id_] := If[beginSelect == 0, beginSelect = id, endSelect = Max[beginSelect, id]]

makeImage[img_, False] := Show[ImagePad[img, 5, White], ImageSize -> 200]
makeImage[img_, True] := Show[ImagePad[img, 5, Red], ImageSize -> 200]

addEventHandler[img_, id_] := EventHandler[
  MouseAppearance[img, "LinkHand"], {
   "MouseClicked" :> selectImage[id]
   }]

displayImages[imgs_] := Grid[Partition[MapThread[
    addEventHandler[
      makeImage[#, beginSelect <= #2 && #2 <= endSelect], #2] &, {
     imgs, Range@Length@imgs
     }], 3]]

Dynamic[Deploy@Column[{
    displayImages[imgs],
    Button["Reset", {beginSelect, endSelect} = {0, 0}]
    }], TrackedSymbols :> {beginSelect, endSelect}]

Demo

You can change the upper limit by selecting a new image that is larger than the lower limit. If you want to change the lower limit then you have to reset and start again. You can modify the reset button to e.g. write beginSelect and endSelect to file, or whatever it is you want to do.

$\endgroup$
  • $\begingroup$ Looks very nice !! I really like the reset button and the nice graphic layout ! Do you think that you could implement multi-labeling (explained in my updated question) ? $\endgroup$ – james Oct 17 '18 at 20:50
  • $\begingroup$ @james I think you should be able to do that yourself, as I've said it's a matter of modifying the reset button. For example, you could create a list labels = {} and a counter i = 0 and then when the reset button is pressed you could run AppendTo[labels, i -> Range[beginSelect, endSelect]]; i++. Now, every time you push the button you add that set of images to a group in the labels variable. Please try, and if you have specific questions about difficulties then I will be happy to help. You could use EventHandler to do this with the keyboard instead of a button if you prefer that. $\endgroup$ – C. E. Oct 18 '18 at 1:45
  • $\begingroup$ I see. Thanks for your suggestion ! I will try it :) $\endgroup$ – james Oct 18 '18 at 5:03
  • $\begingroup$ I have tried to implement it. Please see updated answer. I have a lot of images, so to easily view them, I show a grid of smaller height than all the images and by pushing "next" I can move up the images by 1 row, and by pushing "back", I move the images back down. Now I have two questions: 1. When I click on new label, I want the next image in the row next to the last selected image to be automatically the first selected image for the next labeling task. I don't understand how to implement that. It would be important such that I don't miss any image. $\endgroup$ – james Oct 19 '18 at 19:59
  • $\begingroup$ 2. I would like to have the images that have already been labeled to turn black and white or change color, anything... Thank you so much ! $\endgroup$ – james Oct 19 '18 at 19:59
3
$\begingroup$

Here is a beginning :

imageList=Take[Flatten[ImagePartition[ExampleData[{"TestImage","House"}],{50,50}]],7];

Table[
   With[{i=i},
   Button[
   Dynamic[If[i===start || i===stop || (NumericQ[start] && NumericQ[stop] && start <= i <= stop), Framed[#,Background->Red], #]& @ imageList[[i]]],
   If[CurrentValue["ShiftKey"]===True,stop=i,start=i]
   ]],
{i,1,Length[imageList]}]  

Left-click on the first image of the sequence you want to select.
Shift-left-click on the last image.

The variables startand stop get the indexes of the selection.

enter image description here

Of course, you can apply Row, Column, MultiColumn... on the list of button-images above and the buttons will still work.

$\endgroup$
  • $\begingroup$ Thank you very much ! This is very nice, but can you also include multi-label selection as described in the updated question ? $\endgroup$ – james Oct 17 '18 at 20:48

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.