Skip to content

Commit a2fcc34

Browse files
docs: blur example
1 parent 47465fd commit a2fcc34

File tree

5 files changed

+122
-106
lines changed

5 files changed

+122
-106
lines changed

docs/images/blur-example.png

160 KB
Loading

docs/images/blur-phones.png

216 KB
Loading

docs/pages/examples/blur.md

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Blur image on separated thread
2+
3+
In this example, it will show a way to muddle a photo from a photo gallery using another thread and the WorkletsCore library.
4+
5+
![Example result](../../images/blur-phones.png)
6+
7+
### Requirements
8+
9+
- We must have the react-native-fast-opencv and react-native-worklets-core libraries installed.
10+
- We have a way to handle image from gallery and get it in Base64 format. For this purpose, I used the [react-native-image-picker](https://github.com/react-native-image-picker/react-native-image-picker) library.
11+
12+
### Code
13+
14+
Let's start with a simple code that allows us to select an image from the gallery in Base64 format.
15+
16+
```js
17+
import { useState } from 'react';
18+
import { Button, SafeAreaView, Text } from 'react-native';
19+
import { launchImageLibrary, type Asset } from 'react-native-image-picker';
20+
21+
export function ImageExample() {
22+
const [photo, setPhoto] = useState<Asset | null>(null);
23+
24+
const getImageFromGallery = async () => {
25+
const result = await launchImageLibrary({
26+
mediaType: 'photo',
27+
includeBase64: true,
28+
});
29+
setPhoto(result.assets?.at(0) || null);
30+
};
31+
32+
return (
33+
<SafeAreaView style={{ backgroundColor: 'white', flex: 1 }}>
34+
<Button title="Select photo" onPress={getImageFromGallery} />
35+
<Button title="Process" onPress={() => null} />
36+
</SafeAreaView>
37+
);
38+
}
39+
```
40+
41+
The next step will be to create a function to save the result on the JS thread when the job is done.
42+
43+
```js
44+
const [result, setResult] = useState<string>('');
45+
46+
const setImage = useRunOnJS((data: string) => {
47+
setResult(data);
48+
}, []);
49+
```
50+
51+
Now we will create code that will allow us to perform an action on another thread:
52+
53+
```js
54+
const worklet = useWorklet('default', () => {
55+
'worklet';
56+
if (photo?.base64) {
57+
// ...
58+
}
59+
});
60+
```
61+
62+
Our goal is to apply a simple blur operation using the `blur` function. Then we convert the value to Base64 and display the image.
63+
64+
```js
65+
const src = OpenCV.base64ToMat(photo.base64);
66+
const dst = OpenCV.createObject(ObjectType.Mat, 0, 0, DataTypes.CV_8U);
67+
const kernel = OpenCV.createObject(ObjectType.Size, 1, 1);
68+
const point = OpenCV.createObject(ObjectType.Point, 0, 0);
69+
70+
OpenCV.invoke(
71+
'blur',
72+
src,
73+
dst,
74+
kernel,
75+
point,
76+
BorderTypes.BORDER_DEFAULT
77+
);
78+
const dstResult = OpenCV.toJSValue(dst);
79+
80+
setImage(dstResult.base64);
81+
```
82+
83+
**IMPORTANT.** Remember to remove objects from the memory buffer at the end.
84+
85+
```js
86+
OpenCV.clearBuffers(); // REMEMBER TO CLEAN
87+
```
88+
89+
And ready we can now blur the photo.
90+
91+
![Example result](../../images/blur-example.png)

example/src/App.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ImageExample } from './ImageExample';
22
import { VisionCameraExample } from './VisionCameraExample';
33

44
export default function App() {
5-
const camera = true;
5+
const camera = false;
66

77
if (camera) {
88
return <VisionCameraExample />;

example/src/ImageExample.tsx

+30-105
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,60 @@
11
import { useState } from 'react';
2-
import { Button, Image, SafeAreaView, Text } from 'react-native';
3-
import {
4-
ColorConversionCodes,
5-
ContourApproximationModes,
6-
DataTypes,
7-
ObjectType,
8-
OpenCV,
9-
RetrievalModes,
10-
type Rect,
11-
} from 'react-native-fast-opencv';
2+
import { Button, Image, SafeAreaView } from 'react-native';
3+
import { DataTypes, ObjectType, OpenCV } from 'react-native-fast-opencv';
124
import { launchImageLibrary, type Asset } from 'react-native-image-picker';
13-
import { useRunOnJS, useWorklet, Worklets } from 'react-native-worklets-core';
5+
import { useRunOnJS, useWorklet } from 'react-native-worklets-core';
6+
import { BorderTypes } from '../../src/constants/Core';
147

158
export function ImageExample() {
169
const [photo, setPhoto] = useState<Asset | null>(null);
17-
const [b64, setB64] = useState<string>('');
10+
const [result, setResult] = useState<string>('');
1811

19-
const test = async () => {
12+
const getImageFromGallery = async () => {
2013
const result = await launchImageLibrary({
2114
mediaType: 'photo',
2215
includeBase64: true,
2316
});
2417
setPhoto(result.assets?.at(0) || null);
2518
};
2619

27-
const process = async () => {
28-
if (photo && photo.base64 && photo.width && photo.height) {
20+
const setImage = useRunOnJS((data: string) => {
21+
setResult(data);
22+
}, []);
23+
24+
const worklet = useWorklet('default', () => {
25+
'worklet';
26+
if (photo?.base64) {
2927
const src = OpenCV.base64ToMat(photo.base64);
3028
const dst = OpenCV.createObject(ObjectType.Mat, 0, 0, DataTypes.CV_8U);
29+
const kernel = OpenCV.createObject(ObjectType.Size, 20, 20);
30+
const point = OpenCV.createObject(ObjectType.Point, 0, 0);
3131

32-
await OpenCV.invokeAsync(
33-
'cvtColor',
32+
OpenCV.invoke(
33+
'blur',
3434
src,
3535
dst,
36-
ColorConversionCodes.COLOR_BGR2HSV
36+
kernel,
37+
point,
38+
BorderTypes.BORDER_DEFAULT
3739
);
40+
const dstResult = OpenCV.toJSValue(dst);
3841

39-
const lowerBound = OpenCV.createObject(ObjectType.Scalar, 40, 40, 40);
40-
const upperBound = OpenCV.createObject(ObjectType.Scalar, 100, 255, 255);
41-
42-
await OpenCV.invokeAsync('inRange', dst, lowerBound, upperBound, dst);
43-
44-
// const channels = OpenCV.createObject(ObjectType.MatVector);
45-
// OpenCV.invoke('split', dst, channels);
46-
// const grayChannel = OpenCV.copyObjectFromVector(channels, 0);
47-
48-
// const contours = OpenCV.createObject(ObjectType.MatVector);
49-
50-
// OpenCV.invoke(
51-
// 'findContours',
52-
// grayChannel,
53-
// contours,
54-
// RetrievalModes.RETR_TREE,
55-
// ContourApproximationModes.CHAIN_APPROX_SIMPLE
56-
// );
42+
setImage(dstResult.base64);
5743

58-
// const contoursMats = OpenCV.toJSValue(contours);
59-
60-
// const rectangles: Rect[] = [];
61-
62-
// for (let i = 0; i < contoursMats.array.length; i++) {
63-
// const contour = OpenCV.copyObjectFromVector(contours, i);
64-
// const { value: area } = OpenCV.invoke('contourArea', contour, false);
65-
66-
// if (area > 3000) {
67-
// const rect = OpenCV.invoke('boundingRect', contour);
68-
// rectangles.push(rect);
69-
// }
70-
// }
71-
72-
// console.log(rectangles);
73-
74-
// const result = OpenCV.toJSValue(dst);
75-
// setB64(result.base64);
76-
// console.log(array.length);
44+
OpenCV.clearBuffers(); // IMPORTANT
7745
}
78-
};
79-
80-
const [base64, setBase64] = useState<string>('');
81-
82-
const setImage = useRunOnJS((data: string) => {
83-
setBase64(data);
84-
}, []);
85-
86-
const worklet = useWorklet(
87-
'default',
88-
() => {
89-
'worklet';
90-
if (photo && photo.base64 && photo.width && photo.height) {
91-
const src = OpenCV.base64ToMat(photo.base64);
92-
const dst = OpenCV.createObject(ObjectType.Mat, 0, 0, DataTypes.CV_8U);
93-
94-
OpenCV.invoke('cvtColor', src, dst, ColorConversionCodes.COLOR_BGR2HSV);
95-
96-
const lowerBound = OpenCV.createObject(ObjectType.Scalar, 40, 40, 40);
97-
const upperBound = OpenCV.createObject(
98-
ObjectType.Scalar,
99-
100,
100-
255,
101-
255
102-
);
103-
104-
OpenCV.invoke('inRange', dst, lowerBound, upperBound, dst);
105-
106-
const result = OpenCV.toJSValue(dst);
107-
108-
setImage(result.base64);
109-
}
110-
},
111-
[]
112-
);
46+
});
11347

11448
return (
11549
<SafeAreaView style={{ backgroundColor: 'white', flex: 1 }}>
116-
<Button title="Select photo" onPress={test} />
117-
<Text>
118-
URI: {photo?.uri} {photo?.height} {photo?.width}
119-
</Text>
50+
<Button title="Select photo" onPress={getImageFromGallery} />
12051
<Button title="Process" onPress={() => worklet()} />
121-
{photo?.base64 && photo?.width && photo?.height && (
122-
<Image
123-
source={{ uri: 'data:image/jpg;base64,' + photo.base64 }}
124-
height={300}
125-
width={300}
126-
/>
127-
)}
128-
{b64 && photo?.width && photo?.height && (
52+
53+
{result && (
12954
<Image
130-
source={{ uri: 'data:image/png;base64,' + b64 }}
131-
height={300}
132-
width={300}
55+
source={{ uri: 'data:image/png;base64,' + result }}
56+
height={530}
57+
width={390}
13358
/>
13459
)}
13560
</SafeAreaView>

0 commit comments

Comments
 (0)