Skip to content

Commit f5be4f9

Browse files
Merge branch 'main' into @nk/vision-camera-orientation
2 parents 639cd9c + 3863425 commit f5be4f9

File tree

32 files changed

+1180
-195
lines changed

32 files changed

+1180
-195
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
</h1>
99
</div>
1010

11+
[![Ad](https://revive-adserver.swmansion.com/www/images/zone-gh-react-native-executorch-1?n=1)](https://revive-adserver.swmansion.com/www/delivery/ck.php?zoneid=zone-gh-react-native-executorch-1&n=1)
12+
[![Ad](https://revive-adserver.swmansion.com/www/images/zone-gh-react-native-executorch-2?n=1)](https://revive-adserver.swmansion.com/www/delivery/ck.php?zoneid=zone-gh-react-native-executorch-2&n=1)
13+
[![Ad](https://revive-adserver.swmansion.com/www/images/zone-gh-react-native-executorch-3?n=1)](https://revive-adserver.swmansion.com/www/delivery/ck.php?zoneid=zone-gh-react-native-executorch-3&n=1)
14+
1115
<div align="center">
1216
<a href="https://github.com/software-mansion/react-native-executorch/graphs/contributors"><img src="https://img.shields.io/github/contributors/software-mansion/react-native-executorch?style=for-the-badge&color=00008B" alt="GitHub - Contributors"></a>
1317
<a href="https://github.com/software-mansion/react-native-executorch/stargazers"><img src="https://img.shields.io/github/stars/software-mansion/react-native-executorch?style=for-the-badge&color=00008B" alt="GitHub - Stars"></a>
@@ -60,7 +64,7 @@ React Native ExecuTorch bridges the gap between React Native and native platform
6064
The minimal supported version are:
6165
* iOS 17.0
6266
* Android 13
63-
* React Native 0.81
67+
* React Native - see [compatibility table](https://docs.swmansion.com/react-native-executorch/docs/next/other/compatibility)
6468

6569
> [!IMPORTANT]
6670
> React Native ExecuTorch supports only the [New React Native architecture](https://reactnative.dev/architecture/landing-page).

apps/computer-vision/app/object_detection/index.tsx

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
import Spinner from '../../components/Spinner';
22
import { BottomBar } from '../../components/BottomBar';
3+
import { ModelPicker, ModelOption } from '../../components/ModelPicker';
34
import { getImage } from '../../utils';
45
import {
56
Detection,
67
useObjectDetection,
78
RF_DETR_NANO,
9+
SSDLITE_320_MOBILENET_V3_LARGE,
10+
ObjectDetectionModelSources,
811
} from 'react-native-executorch';
912
import { View, StyleSheet, Image } from 'react-native';
1013
import ImageWithBboxes from '../../components/ImageWithBboxes';
1114
import React, { useContext, useEffect, useState } from 'react';
1215
import { GeneratingContext } from '../../context';
1316
import ScreenWrapper from '../../ScreenWrapper';
1417

18+
const MODELS: ModelOption<ObjectDetectionModelSources>[] = [
19+
{ label: 'RF-DeTR Nano', value: RF_DETR_NANO },
20+
{ label: 'SSDLite MobileNet', value: SSDLITE_320_MOBILENET_V3_LARGE },
21+
];
22+
1523
export default function ObjectDetectionScreen() {
1624
const [imageUri, setImageUri] = useState('');
1725
const [results, setResults] = useState<Detection[]>([]);
1826
const [imageDimensions, setImageDimensions] = useState<{
1927
width: number;
2028
height: number;
2129
}>();
30+
const [selectedModel, setSelectedModel] =
31+
useState<ObjectDetectionModelSources>(RF_DETR_NANO);
2232

23-
const rfDetr = useObjectDetection({ model: RF_DETR_NANO });
33+
const model = useObjectDetection({ model: selectedModel });
2434
const { setGlobalGenerating } = useContext(GeneratingContext);
2535
useEffect(() => {
26-
setGlobalGenerating(rfDetr.isGenerating);
27-
}, [rfDetr.isGenerating, setGlobalGenerating]);
36+
setGlobalGenerating(model.isGenerating);
37+
}, [model.isGenerating, setGlobalGenerating]);
2838

2939
const handleCameraPress = async (isCamera: boolean) => {
3040
const image = await getImage(isCamera);
@@ -42,19 +52,19 @@ export default function ObjectDetectionScreen() {
4252
const runForward = async () => {
4353
if (imageUri) {
4454
try {
45-
const output = await rfDetr.forward(imageUri);
55+
const output = await model.forward(imageUri);
4656
setResults(output);
4757
} catch (e) {
4858
console.error(e);
4959
}
5060
}
5161
};
5262

53-
if (!rfDetr.isReady) {
63+
if (!model.isReady) {
5464
return (
5565
<Spinner
56-
visible={!rfDetr.isReady}
57-
textContent={`Loading the model ${(rfDetr.downloadProgress * 100).toFixed(0)} %`}
66+
visible={!model.isReady}
67+
textContent={`Loading the model ${(model.downloadProgress * 100).toFixed(0)} %`}
5868
/>
5969
);
6070
}
@@ -81,6 +91,15 @@ export default function ObjectDetectionScreen() {
8191
)}
8292
</View>
8393
</View>
94+
<ModelPicker
95+
models={MODELS}
96+
selectedModel={selectedModel}
97+
disabled={model.isGenerating}
98+
onSelect={(m) => {
99+
setSelectedModel(m);
100+
setResults([]);
101+
}}
102+
/>
84103
<BottomBar
85104
handleCameraPress={handleCameraPress}
86105
runForward={runForward}
@@ -100,31 +119,6 @@ const styles = StyleSheet.create({
100119
borderRadius: 8,
101120
width: '100%',
102121
},
103-
results: {
104-
flex: 1,
105-
alignItems: 'center',
106-
justifyContent: 'center',
107-
gap: 4,
108-
padding: 4,
109-
},
110-
resultHeader: {
111-
fontSize: 18,
112-
color: 'navy',
113-
},
114-
resultsList: {
115-
flex: 1,
116-
},
117-
resultRecord: {
118-
flexDirection: 'row',
119-
width: '100%',
120-
justifyContent: 'space-between',
121-
padding: 8,
122-
borderBottomWidth: 1,
123-
},
124-
resultLabel: {
125-
flex: 1,
126-
marginRight: 4,
127-
},
128122
fullSizeImage: {
129123
width: '100%',
130124
height: '100%',

apps/computer-vision/app/ocr/index.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,48 @@
11
import Spinner from '../../components/Spinner';
22
import { BottomBar } from '../../components/BottomBar';
3+
import { ModelPicker, ModelOption } from '../../components/ModelPicker';
34
import { getImage } from '../../utils';
4-
import { useOCR, OCR_ENGLISH } from 'react-native-executorch';
5+
import {
6+
useOCR,
7+
OCR_ENGLISH,
8+
OCR_GERMAN,
9+
OCR_FRENCH,
10+
OCR_SPANISH,
11+
OCR_ITALIAN,
12+
OCR_JAPANESE,
13+
OCR_KOREAN,
14+
OCRProps,
15+
} from 'react-native-executorch';
516
import { View, StyleSheet, Image, Text, ScrollView } from 'react-native';
617
import ImageWithBboxes2 from '../../components/ImageWithOCRBboxes';
718
import React, { useContext, useEffect, useState } from 'react';
819
import { GeneratingContext } from '../../context';
920
import ScreenWrapper from '../../ScreenWrapper';
1021

22+
type OCRModelSources = OCRProps['model'];
23+
24+
const MODELS: ModelOption<OCRModelSources>[] = [
25+
{ label: 'English', value: OCR_ENGLISH },
26+
{ label: 'German', value: OCR_GERMAN },
27+
{ label: 'French', value: OCR_FRENCH },
28+
{ label: 'Spanish', value: OCR_SPANISH },
29+
{ label: 'Italian', value: OCR_ITALIAN },
30+
{ label: 'Japanese', value: OCR_JAPANESE },
31+
{ label: 'Korean', value: OCR_KOREAN },
32+
];
33+
1134
export default function OCRScreen() {
1235
const [imageUri, setImageUri] = useState('');
1336
const [results, setResults] = useState<any[]>([]);
1437
const [imageDimensions, setImageDimensions] = useState<{
1538
width: number;
1639
height: number;
1740
}>();
41+
const [selectedModel, setSelectedModel] =
42+
useState<OCRModelSources>(OCR_ENGLISH);
1843

1944
const model = useOCR({
20-
model: OCR_ENGLISH,
45+
model: selectedModel,
2146
});
2247
const { setGlobalGenerating } = useContext(GeneratingContext);
2348
useEffect(() => {
@@ -89,6 +114,15 @@ export default function OCRScreen() {
89114
</View>
90115
)}
91116
</View>
117+
<ModelPicker
118+
models={MODELS}
119+
selectedModel={selectedModel}
120+
disabled={model.isGenerating}
121+
onSelect={(m) => {
122+
setSelectedModel(m);
123+
setResults([]);
124+
}}
125+
/>
92126
<BottomBar
93127
handleCameraPress={handleCameraPress}
94128
runForward={runForward}

apps/computer-vision/app/semantic_segmentation/index.tsx

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import Spinner from '../../components/Spinner';
22
import { BottomBar } from '../../components/BottomBar';
3+
import { ModelPicker, ModelOption } from '../../components/ModelPicker';
34
import { getImage } from '../../utils';
45
import {
56
DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED,
7+
DEEPLAB_V3_RESNET50_QUANTIZED,
8+
DEEPLAB_V3_RESNET101_QUANTIZED,
9+
LRASPP_MOBILENET_V3_LARGE_QUANTIZED,
10+
FCN_RESNET50_QUANTIZED,
11+
FCN_RESNET101_QUANTIZED,
612
useSemanticSegmentation,
13+
SemanticSegmentationModelSources,
714
} from 'react-native-executorch';
815
import {
916
Canvas,
@@ -42,12 +49,28 @@ const numberToColor: number[][] = [
4249
[162, 51, 255], // 20 Amethyst
4350
];
4451

52+
const MODELS: ModelOption<SemanticSegmentationModelSources>[] = [
53+
{
54+
label: 'DeepLab MobileNet',
55+
value: DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED,
56+
},
57+
{ label: 'DeepLab ResNet50', value: DEEPLAB_V3_RESNET50_QUANTIZED },
58+
{ label: 'DeepLab ResNet101', value: DEEPLAB_V3_RESNET101_QUANTIZED },
59+
{ label: 'LRASPP MobileNet', value: LRASPP_MOBILENET_V3_LARGE_QUANTIZED },
60+
{ label: 'FCN ResNet50', value: FCN_RESNET50_QUANTIZED },
61+
{ label: 'FCN ResNet101', value: FCN_RESNET101_QUANTIZED },
62+
];
63+
4564
export default function SemanticSegmentationScreen() {
4665
const { setGlobalGenerating } = useContext(GeneratingContext);
66+
const [selectedModel, setSelectedModel] =
67+
useState<SemanticSegmentationModelSources>(
68+
DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED
69+
);
70+
4771
const { isReady, isGenerating, downloadProgress, forward } =
48-
useSemanticSegmentation({
49-
model: DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED,
50-
});
72+
useSemanticSegmentation({ model: selectedModel });
73+
5174
const [imageUri, setImageUri] = useState('');
5275
const [imageSize, setImageSize] = useState({ width: 0, height: 0 });
5376
const [segImage, setSegImage] = useState<SkImage | null>(null);
@@ -61,10 +84,7 @@ export default function SemanticSegmentationScreen() {
6184
const image = await getImage(isCamera);
6285
if (!image?.uri) return;
6386
setImageUri(image.uri);
64-
setImageSize({
65-
width: image.width ?? 0,
66-
height: image.height ?? 0,
67-
});
87+
setImageSize({ width: image.width ?? 0, height: image.height ?? 0 });
6888
setSegImage(null);
6989
};
7090

@@ -150,6 +170,15 @@ export default function SemanticSegmentationScreen() {
150170
</View>
151171
)}
152172
</View>
173+
<ModelPicker
174+
models={MODELS}
175+
selectedModel={selectedModel}
176+
disabled={isGenerating}
177+
onSelect={(m) => {
178+
setSelectedModel(m);
179+
setSegImage(null);
180+
}}
181+
/>
153182
<BottomBar
154183
handleCameraPress={handleCameraPress}
155184
runForward={runForward}
@@ -159,29 +188,15 @@ export default function SemanticSegmentationScreen() {
159188
}
160189

161190
const styles = StyleSheet.create({
162-
imageCanvasContainer: {
163-
flex: 6,
164-
width: '100%',
165-
padding: 16,
166-
},
167-
imageContainer: {
168-
flex: 1,
169-
width: '100%',
170-
},
171-
image: {
172-
flex: 1,
173-
borderRadius: 8,
174-
width: '100%',
175-
},
191+
imageCanvasContainer: { flex: 6, width: '100%', padding: 16 },
192+
imageContainer: { flex: 1, width: '100%' },
193+
image: { flex: 1, borderRadius: 8, width: '100%' },
176194
canvasContainer: {
177195
flex: 1,
178196
justifyContent: 'center',
179197
alignItems: 'center',
180198
gap: 4,
181199
padding: 4,
182200
},
183-
canvas: {
184-
width: '100%',
185-
height: '100%',
186-
},
201+
canvas: { width: '100%', height: '100%' },
187202
});

apps/computer-vision/app/style_transfer/index.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
import Spinner from '../../components/Spinner';
22
import { BottomBar } from '../../components/BottomBar';
3+
import { ModelPicker, ModelOption } from '../../components/ModelPicker';
34
import { getImage } from '../../utils';
45
import {
56
useStyleTransfer,
67
STYLE_TRANSFER_CANDY_QUANTIZED,
8+
STYLE_TRANSFER_MOSAIC_QUANTIZED,
9+
STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED,
10+
STYLE_TRANSFER_UDNIE_QUANTIZED,
11+
StyleTransferModelName,
12+
ResourceSource,
713
} from 'react-native-executorch';
14+
815
import { View, StyleSheet, Image } from 'react-native';
916
import React, { useContext, useEffect, useState } from 'react';
1017
import { GeneratingContext } from '../../context';
1118
import ScreenWrapper from '../../ScreenWrapper';
1219

20+
type StyleTransferModelSources = {
21+
modelName: StyleTransferModelName;
22+
modelSource: ResourceSource;
23+
};
24+
25+
const MODELS: ModelOption<StyleTransferModelSources>[] = [
26+
{ label: 'Candy', value: STYLE_TRANSFER_CANDY_QUANTIZED },
27+
{ label: 'Mosaic', value: STYLE_TRANSFER_MOSAIC_QUANTIZED },
28+
{ label: 'Rain Princess', value: STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED },
29+
{ label: 'Udnie', value: STYLE_TRANSFER_UDNIE_QUANTIZED },
30+
];
31+
1332
export default function StyleTransferScreen() {
14-
const model = useStyleTransfer({ model: STYLE_TRANSFER_CANDY_QUANTIZED });
33+
const [selectedModel, setSelectedModel] = useState<StyleTransferModelSources>(
34+
STYLE_TRANSFER_CANDY_QUANTIZED
35+
);
36+
37+
const model = useStyleTransfer({ model: selectedModel });
1538
const { setGlobalGenerating } = useContext(GeneratingContext);
1639
useEffect(() => {
1740
setGlobalGenerating(model.isGenerating);
@@ -64,6 +87,15 @@ export default function StyleTransferScreen() {
6487
}
6588
/>
6689
</View>
90+
<ModelPicker
91+
models={MODELS}
92+
selectedModel={selectedModel}
93+
disabled={model.isGenerating}
94+
onSelect={(m) => {
95+
setSelectedModel(m);
96+
setStyledUri('');
97+
}}
98+
/>
6799
<BottomBar
68100
handleCameraPress={handleCameraPress}
69101
runForward={runForward}
@@ -73,14 +105,6 @@ export default function StyleTransferScreen() {
73105
}
74106

75107
const styles = StyleSheet.create({
76-
imageContainer: {
77-
flex: 6,
78-
width: '100%',
79-
padding: 16,
80-
},
81-
image: {
82-
flex: 1,
83-
borderRadius: 8,
84-
width: '100%',
85-
},
108+
imageContainer: { flex: 6, width: '100%', padding: 16 },
109+
image: { flex: 1, borderRadius: 8, width: '100%' },
86110
});

0 commit comments

Comments
 (0)