How to create a MLImageClassifier in Xcode 10 - swift

I'm trying to build a Machine Learning - Image Recognition using Create ML in Xcode 10.1 Playground but I'm having some problems to put my data in the model.
I have a folder with images numbered from 1 to 1336 and a .csv file with 2 columns (the image name and the image classification).
I don't know exactly how to put this in the model.
I have this until now:
import Cocoa
import CreateML
let data = try MLDataTable(contentsOf: URL(fileURLWithPath: "/Users/x/Desktop/CoreML/project/file.csv"))
let(trainingData, testingData) = data.randomSplit(by: 0.8, seed: 1)
let Classifier = try MLImageClassifier *need help here*
let evaluationMetrics = sentimentClassifier.evaluation(on: testingData)
let evaluationAccuracy = (1 - evaluationMetrics.classificationError) * 100
let metaData = MLModelMetadata(author: "x", shortDescription: "Model", version: "1.0")
try classifier.write(to: URL(fileURLWithPath: "/Users/x/Desktop/CoreML/project/XClassifier.mlmodel"))

I believe it is not possible to feed labels to MLImageClassifier via .csv or any other separate file. You have only two options: use file names as labels or use directories as labels (probably preferable in your case of many images):
let model = try MLImageClassifier(trainingData: .labeledDirectories(at: trainingDir))
let evaluation = model.evaluation(on: .labeledDirectories(at: testingDir))
You will need to put images into subdirectories named as labels in your .csv file.

I was just struggling with this myself. Here is a solution to re-organise data for CreateML. All credit goes to Tony T1 who came up with this script.
Place images and CSV file into a single folder.
In Automator, create a new workflow like this:
Run the workflow. Select your CSV and watch the images get sorted into their respective folders!
The script is as follows:
cd "${1%/*}"
while read line
do
FolderName=${line%;*}
ImageName=${line#*;}
mkdir "$FolderName"
mv "$ImageName" "$FolderName"
done < "$1"
DF20 is the starting folder, you can change that to whatever you wish
my CSV was separated by ";". If your CSV is separated by ",", change that symbol in the script (e.g. FolderName=${line%,*} )
In my CSV, classes were columnA and images columnB. Switch this around depending on your case.

Related

An error occurs when using MLDataTable to load data

I tried to create a word tagger model in Swift according to this tutorial in the latest XCode. But I cannot load data from a local file using MLDataTable. Here is my code.
let data = try MLDataTable(contentsOf:
URL(fileURLWithPath: "/path/to/data.json"))
The error is as follows.
error: Couldn't lookup symbols:
CreateML.MLDataTable.init(contentsOf: Foundation.URL, options:
CreateML.MLDataTable.ParsingOptions) throws -> CreateML.MLDataTable
I tried absolute path and relative path, but neither of them worked(I am pretty sure that the data file is in the right location and the paths are correct). In addition, I can load the local file to a URL object, so the problem should lie in MLDataTable.
Could someone help?
I have the same error however I used .csv file. But the problem is solved when I use COREML tool under developer tools of Xcode.
Here are some recommendations:
Your training data's class column label should be "label"
Your training data can be one file but testing data should contains sub folders named exactly the same name of your label's names. To illustrate, you have "negative", "positive" and "neutral as label names. Then you should have three sub folders named "negative", "positive" and "neutral". Moreover testing data files can't be one json or csv file including all the testing data. For example if you have five rows of negative labeled data, you can't put that csv file under negative sub-folder. You have to create five txt file for each five row.

Matlab: labeling images stored in a single file based on image name

I was assigned a matlab assignment where I was given 25000 pictures of cats and dogs all stored in one folder. My question is how can I use the imagedatastore function on matlab to store these files into one single variable containing two labels (cats and dogs). Each image stored in the file follow the following format:
cat.1.png,
cat.2.png,
.....,
cat.N.png,
dog.1.png,
dog.2.png,
.....,
dog.N.png,
Ideally I think labeling them based on image name would probably be the best approach to this. How ever I've tired doing this using various implementations methods but I keep failing. Any advice on this would be greatly appreciated!
The steps for both image data stores are the same:
Find all the image files with a matching name with dir.
Rebuild the full path to these files with fullfile.
Create the image data store with the files.
My code assumes that you are running the script in the same folder in which images are located. Here is the code:
cats = dir('cat.*.png');
files_cats = fullfile({cats.folder}.', {cats.name}.');
imds_cats = imageDatastore(files_cats);
dogs = dir('dog.*.png');
files_dogs = fullfile({dogs.folder}.', {dogs.name}.');
imds_dogs = imageDatastore(files_dogs);
You could also use the short path:
imds_cats = imageDatastore('cat.*.png');
imds_dogs = imageDatastore('dog.*.png');
If you want to use a single image data store and split files into categories within it (without using folder names, since all your files seem to be located in the same directory):
cats = dir('cat.*.png');
cats_labs = repmat({'Cat'},numel(cats),1);
dogs = dir('dog.*.png');
dogs_labs = repmat({'Dog'},numel(dogs),1);
labs = [cats_labs; dogs_labs];
imds = imageDatastore({'cat.*.png' 'dog.*.png'},'Labels',labs);

Bundle.main.path does not find text file added in project

I have a command line project in Xcode 9 and I'm trying to read a text file I added to the project via "Add files to...". I'm using the following line to grab the path to the file:
guard let filePath = Bundle.main.path(forResource: "stops", ofType: "csv") else {
fatalError("Cannot find CSV file")
}
When I run it, it prints out the fatalError message. I tried adding the text file in the "Copy Bundle Resources" build phase. It still doesn't find the file.
What am I doing wrong?
Early last year I had this same issue - here is my workaround (and I must stress that this is a work around, hopefully there is another way to do it now)
Create a Swift file in your project that you can use to access the data (mine was Recipe.swift)
Drop your CSV into xcode (ignoring target membership - just for convenience (mine was Recipe.json))
Create a run script phase to load the data from your CSV to into a Swift class:
set -e
DATA=$(cat "./MyProject/recipe.json" | base64)
echo "import Foundation" > "./MyProject/Recipe.swift"
echo "class Recipe {" >> "./MyProject/Recipe.swift"
echo " static let data = \"$DATA\"" >> "./MyProject/Recipe.swift"
echo "}" >> "./MyProject/Recipe.swift"
This generates a class in your Swift file that looks something like:
import Foundation
class Recipe {
static let data = "..."
}
And then you can decode Recipe.data when you need to use it.
Of course this isn't a very expandable solution, and I'm sure you can make it better by using lazy initialization, adding the base64 decode directly in the generated class, making paths in the script relative to $SRCROOT etc. This was just my quick solution that allowed me to continue working on the rest of the project.
The issue for me was I have created first a ResponseJSON.swift then rename it to ResponseJSON.json (changed to .json extension) and it was not being detected.
Solution:
Remove the reference of the file
Adding it again on Xcode
Compile and smile while you cry with those Xcode bugs :)

How to combine several PNG images as layers in a single XCF image?

I have several PNG images, which I need to combine as individual layers in a new GIMP XCF image. I need to perform this task many times, so a script based solution would be best.
So far i tried to play around with the batch mode of GIMP, but failed miserably.
Instead of script-fu, which uses Scheme, I'd recommend using the GIMP-Python binding for this, since it is far easier to manipulate files and listings.
If you check filters->Python->Console you will b dropped into an interactive mode - at the bottom of it, there will be a "Browse" button which lets you select any of GIMP's procedures in its API and paste it directly in this console.
There is as an API call to "load a file as a layer" - pdb.gimp_file_load_layer -
this however, brings the image to memory, but do not add it to the image - you have to call
pdb.gimp_image_insert_layer afterwards
You can type this directly in the interactive console, or,check one of my other GIMP-related answers, or some resource on GIMP-Python on the web to convert it to a plug-in, which won't require pasting this code each time you want to perform the task:
def open_images_as_layers(img, image_file_list):
for image_name in image_file_list:
layer = pdb.gimp_file_load_layer(image_name)
pdb.gimp_image_insert_layer(img, layer, None, 0)
img = gimp.image_list()[0]
image_list = "temp1.png temp2.png temp3.png"
open_images_as_layers(img, image_list.split())
The second to last line img = ... picks a needed reference to an open image
in GIMP - you could also create a new image using pdb calls if you'd prefer
(example bellow).
The file list is a hardcoded space separated string in the snippet above,
but you can create the file list in any of the ways allowed by Python.
For example, to get all the ".png" file names in a
c:\Documents and Settings\My user\Pictures folder, you could do:
from glob import glob
image_list = glob("c:/Documents and Settings/My user/Pictures/*png")
To create an image programatically:
img = gimp.Image(1024, 768)
pdb.gimp_display_new(img)

load files from two different folders in matlab

Hi and I am little bit new in matlab.
I have two different folders in my laptop, each one contains about 400 different files. I want to load all these files (400 from first folder and 400 from second folder), I tried like that but doesn't work:
folder1=('E:\results\1\');
folder2=('E:\results\2\');
data=load([folder1,'*.m']);
data1=load([folder2,'*.m']);
and then I want to take first file from folder1 and subtracted from first file from folder1 and save it in new folder. and do that for all other files ... etc
can some expert give me any suggerstion!!
thanks in advance.
Pretty sure load takes one file at a time. Try a simple variant like this:
folder1=('E:\results\1\');
folder2=('E:\results\2\');
files1 = dir( [folder1,'*.m'] );
files2 = dir( [folder2,'*.m'] );
data = cell(length(files1),1); % I don't know what's in the mat files, but let's start with a cell array
data1 = cell(length(files2),1);
for ii=1:length(files1)
data{ii} = load(fullfile(folder1,files1(ii).name));
end
for ii=1:length(files2)
data1{ii} = load(fullfile(folder2,files2(ii).name));
end
There are other, more one liner ways, but this is a fairly pedantic.