Repository: deepjavalibrary/djl
Pull request #1355 (2021-11-09 17:47:07)

[api] Adds Image.duplicate() back
Change-Id: Ic45f668591f4677708e40090f3ea9487a098e3fb

## Description ##

Brief description of what this PR is about

- If this change is a backward incompatible change, why must this change be made?
- Interesting edge cases to note here


codecov-commenter: # [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) Report
> Merging [#1355](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (c96c8ce) into [master](https://codecov.io/gh/deepjavalibrary/djl/commit/bb5073f7ffc33f1883621fc1783dbb01e70b418f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (bb5073f) will **decrease** coverage by `0.38%`.
> The diff coverage is `61.77%`.

[![Impacted file tree graph](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/graphs/tree.svg?width=650&height=150&src=pr&token=mDKVNwFXRV&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)

```diff
@@             Coverage Diff              @@
##             master    #1355      +/-   ##
============================================
- Coverage     72.08%   71.69%   -0.39%     
- Complexity     5126     5183      +57     
============================================
  Files           473      480       +7     
  Lines         21970    22473     +503     
  Branches       2351     2413      +62     
============================================
+ Hits          15838    16113     +275     
- Misses         4925     5133     +208     
- Partials       1207     1227      +20     
```


| [Impacted Files](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | Coverage Δ | |
|---|---|---|
| [api/src/main/java/ai/djl/modality/cv/Image.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L0ltYWdlLmphdmE=) | `69.23% <ø> (-4.11%)` | :arrow_down: |
| [...i/djl/modality/cv/translator/BigGANTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvci5qYXZh) | `21.42% <ø> (-5.24%)` | :arrow_down: |
| [...odality/cv/translator/BigGANTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvckZhY3RvcnkuamF2YQ==) | `33.33% <0.00%> (+8.33%)` | :arrow_up: |
| [...nslator/InstanceSegmentationTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvSW5zdGFuY2VTZWdtZW50YXRpb25UcmFuc2xhdG9yRmFjdG9yeS5qYXZh) | `14.28% <0.00%> (-3.90%)` | :arrow_down: |
| [.../modality/cv/translator/YoloTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvWW9sb1RyYW5zbGF0b3JGYWN0b3J5LmphdmE=) | `8.33% <0.00%> (-1.67%)` | :arrow_down: |
| [...i/djl/modality/cv/translator/YoloV5Translator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvWW9sb1Y1VHJhbnNsYXRvci5qYXZh) | `5.69% <0.00%> (ø)` | |
| [...odality/cv/translator/YoloV5TranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvWW9sb1Y1VHJhbnNsYXRvckZhY3RvcnkuamF2YQ==) | `8.33% <0.00%> (-1.67%)` | :arrow_down: |
| [...modality/nlp/embedding/TrainableWordEmbedding.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L25scC9lbWJlZGRpbmcvVHJhaW5hYmxlV29yZEVtYmVkZGluZy5qYXZh) | `45.00% <0.00%> (-3.34%)` | :arrow_down: |
| [...pi/src/main/java/ai/djl/ndarray/BytesSupplier.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL25kYXJyYXkvQnl0ZXNTdXBwbGllci5qYXZh) | `54.54% <0.00%> (-12.13%)` | :arrow_down: |
| [...i/src/main/java/ai/djl/ndarray/NDArrayAdapter.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL25kYXJyYXkvTkRBcnJheUFkYXB0ZXIuamF2YQ==) | `15.23% <0.00%> (-0.83%)` | :arrow_down: |
| ... and [120 more](https://codecov.io/gh/deepjavalibrary/djl/pull/1355/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Last update [5ce3525...c96c8ce](https://codecov.io/gh/deepjavalibrary/djl/pull/1355?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).


Patch:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..1f9d3db0a
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# Global Owners
+* @zachgk @frankfliu
\ No newline at end of file
diff --git a/api/src/main/java/ai/djl/modality/cv/BufferedImageFactory.java b/api/src/main/java/ai/djl/modality/cv/BufferedImageFactory.java
index 254dbcf98..19956f893 100644
--- a/api/src/main/java/ai/djl/modality/cv/BufferedImageFactory.java
+++ b/api/src/main/java/ai/djl/modality/cv/BufferedImageFactory.java
@@ -31,6 +31,7 @@ import java.awt.FontMetrics;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -165,6 +166,17 @@ public class BufferedImageFactory extends ImageFactory {
             return new BufferedImageWrapper(image.getSubimage(x, y, w, h));
         }
 
+        /** {@inheritDoc} */
+        @Override
+        public Image duplicate() {
+            BufferedImage copy =
+                    new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
+            byte[] sourceData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
+            byte[] biData = ((DataBufferByte) copy.getRaster().getDataBuffer()).getData();
+            System.arraycopy(sourceData, 0, biData, 0, sourceData.length);
+            return new BufferedImageWrapper(copy);
+        }
+
         private void convertIdNeeded() {
             if (image.getType() == BufferedImage.TYPE_INT_ARGB) {
                 return;
diff --git a/api/src/main/java/ai/djl/modality/cv/Image.java b/api/src/main/java/ai/djl/modality/cv/Image.java
index eaa26af1b..dea29361f 100644
--- a/api/src/main/java/ai/djl/modality/cv/Image.java
+++ b/api/src/main/java/ai/djl/modality/cv/Image.java
@@ -57,6 +57,13 @@ public interface Image {
      */
     Image getSubImage(int x, int y, int w, int h);
 
+    /**
+     * Gets a deep copy of the original image.
+     *
+     * @return the copy of the original image.
+     */
+    Image duplicate();
+
     /**
      * Converts image to a RGB {@link NDArray}.
      *
diff --git a/docs/development/dependency_management.md b/docs/development/dependency_management.md
index c51cf68df..0cfd9b3db 100644
--- a/docs/development/dependency_management.md
+++ b/docs/development/dependency_management.md
@@ -124,3 +124,7 @@ See [How to use DJL's BOM](../../bom/README.md#how-to-use-djls-bom) for detail.
 | [ai.djl.hadoop](https://search.maven.org/search?q=g:ai.djl.hadoop) | [hadoop](../../extensions/hadoop/README.md#installation) | Contains classes that make it easy for DJL access HDFS |
 | | | |
 | [ai.djl.sentencepiece](https://search.maven.org/search?q=g:ai.djl.sentencepiece) | [sentencepiece](../../extensions/sentencepiece/README.md#installation) | Contains NLP utility classes NLP for SentencePiece |
+| | | |
+| [ai.djl.opencv](https://search.maven.org/search?q=g:ai.djl.opencv) | [opencv](../../extensions/opencv/README.md#installation) | DJL OpenCV extension for high performance image processing |
+| | | |
+| [ai.djl.serving](https://search.maven.org/search?q=g:ai.djl.serving) | [wlm](https://github.com/deepjavalibrary/djl-serving/tree/master/wlm) | DJL Serving WorkLoadManager |
diff --git a/engines/pytorch/pytorch-engine/README.md b/engines/pytorch/pytorch-engine/README.md
index b345d3781..b2d7f6c6d 100644
--- a/engines/pytorch/pytorch-engine/README.md
+++ b/engines/pytorch/pytorch-engine/README.md
@@ -38,13 +38,17 @@ You can pull the PyTorch engine from the central Maven repository by including t
 Besides the `pytorch-engine` library, you may also need to include the PyTorch native library in your project.
 All current provided PyTorch native libraries are downloaded from [PyTorch C++ distribution](https://pytorch.org/get-started/locally/#start-locally).
 
-In current implementation, one version of pytorch-engine can only load a specific version of pytorch native library.
+Since DJL 0.14.0, `pytorch-engine` can load older version of pytorch native library. There are two
+ways to specify PyTorch version:
+
+1. Explicitly specify `pytorch-native-xxx` package version to override the version in the [BOM](../../../bom/README.md).
+2. Sets environment variable: `PYTORCH_VERSION` to override the package version defined by `pytorch-native-auto`.
 
 The following table illustrates which pytorch version that DJL supports:
 
 | PyTorch engine version | PyTorch native library version           |
 |------------------------|------------------------------------------|
-| pytorch-engine:0.14.0  | pytorch-native-auto:1.9.1                |
+| pytorch-engine:0.14.0  | pytorch-native-auto: 1.8.1, 1.9.0, 1.9.1 |
 | pytorch-engine:0.13.0  | pytorch-native-auto:1.9.0                |
 | pytorch-engine:0.12.0  | pytorch-native-auto:1.8.1                |
 | pytorch-engine:0.11.0  | pytorch-native-auto:1.8.1                |
@@ -65,13 +69,16 @@ Choose a native library based on your platform and needs:
 We offer an automatic option that will download the native libraries into [cache folder](../../../docs/development/cache_management.md) the first time you run DJL.
 It will automatically determine the appropriate jars for your system based on the platform and GPU support.
 
-- ai.djl.pytorch:pytorch-native-auto:1.9.0
+Since DJL 0.14.0, the auto package is optional, DJL will download the latest pytorch native library
+if no `pytorch-native-auto` package is included.
+
+- ai.djl.pytorch:pytorch-native-auto:1.9.1
 
 ```xml
 <dependency>
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-auto</artifactId>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
@@ -79,14 +86,14 @@ It will automatically determine the appropriate jars for your system based on th
 ### macOS
 For macOS, you can use the following library:
 
-- ai.djl.pytorch:pytorch-native-cpu:1.9.0:osx-x86_64
+- ai.djl.pytorch:pytorch-native-cpu:1.9.1:osx-x86_64
 
 ```xml
 <dependency>
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cpu</artifactId>
     <classifier>osx-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
@@ -97,15 +104,15 @@ installed on your GPU machine, you can use one of the following library:
 
 #### Linux GPU
 
-- ai.djl.pytorch:pytorch-native-cu111:1.9.0:linux-x86_64 - CUDA 11.1
-- ai.djl.pytorch:pytorch-native-cu102:1.9.0:linux-x86_64 - CUDA 10.2
+- ai.djl.pytorch:pytorch-native-cu111:1.9.1:linux-x86_64 - CUDA 11.1
+- ai.djl.pytorch:pytorch-native-cu102:1.9.1:linux-x86_64 - CUDA 10.2
 
 ```xml
 <dependency>
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cu111</artifactId>
     <classifier>linux-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
@@ -115,14 +122,14 @@ installed on your GPU machine, you can use one of the following library:
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cu102</artifactId>
     <classifier>linux-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
 
 ### Linux CPU
 
-- ai.djl.pytorch:pytorch-native-cpu:1.9.0:linux-x86_64
+- ai.djl.pytorch:pytorch-native-cpu:1.9.1:linux-x86_64
 
 ```xml
 <dependency>
@@ -130,7 +137,7 @@ installed on your GPU machine, you can use one of the following library:
     <artifactId>pytorch-native-cpu</artifactId>
     <classifier>linux-x86_64</classifier>
     <scope>runtime</scope>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
 </dependency>
 ```
 
@@ -139,14 +146,14 @@ installed on your GPU machine, you can use one of the following library:
 We also provide packages for the system like CentOS 7/Ubuntu 14.04 with GLIBC >= 2.17.
 All the package were built with GCC 7, we provided a newer `libstdc++.so.6.24` in the package that contains `CXXABI_1.3.9` to use the package successfully.
 
-- ai.djl.pytorch:pytorch-native-cpu-precxx11:1.9.0:linux-x86_64
+- ai.djl.pytorch:pytorch-native-cpu-precxx11:1.9.1:linux-x86_64
 
 ```xml
 <dependency>
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cpu-precxx11</artifactId>
     <classifier>linux-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
@@ -161,15 +168,15 @@ For the Windows platform, you can choose between CPU and GPU.
 
 #### Windows GPU
 
-- ai.djl.pytorch:pytorch-native-cu111:1.9.0:win-x86_64
-- ai.djl.pytorch:pytorch-native-cu102:1.9.0:win-x86_64
+- ai.djl.pytorch:pytorch-native-cu111:1.9.1:win-x86_64
+- ai.djl.pytorch:pytorch-native-cu102:1.9.1:win-x86_64
 
 ```xml
 <dependency>
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cu111</artifactId>
     <classifier>win-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
@@ -179,14 +186,14 @@ For the Windows platform, you can choose between CPU and GPU.
     <groupId>ai.djl.pytorch</groupId>
     <artifactId>pytorch-native-cu102</artifactId>
     <classifier>win-x86_64</classifier>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
     <scope>runtime</scope>
 </dependency>
 ```
 
 ### Windows CPU
 
-- ai.djl.pytorch:pytorch-native-cpu:1.9.0:win-x86_64
+- ai.djl.pytorch:pytorch-native-cpu:1.9.1:win-x86_64
 
 ```xml
 <dependency>
@@ -194,6 +201,6 @@ For the Windows platform, you can choose between CPU and GPU.
     <artifactId>pytorch-native-cpu</artifactId>
     <classifier>win-x86_64</classifier>
     <scope>runtime</scope>
-    <version>1.9.0</version>
+    <version>1.9.1</version>
 </dependency>
 ```
diff --git a/examples/build.gradle b/examples/build.gradle
index c65469efd..da5d70095 100644
--- a/examples/build.gradle
+++ b/examples/build.gradle
@@ -15,7 +15,6 @@ dependencies {
     testImplementation("org.testng:testng:${testng_version}") {
         exclude group: "junit", module: "junit"
     }
-    testImplementation project(":testing")
 }
 
 application {
diff --git a/extensions/opencv/src/main/java/ai/djl/opencv/OpenCVImage.java b/extensions/opencv/src/main/java/ai/djl/opencv/OpenCVImage.java
index 316008932..5eb16744e 100644
--- a/extensions/opencv/src/main/java/ai/djl/opencv/OpenCVImage.java
+++ b/extensions/opencv/src/main/java/ai/djl/opencv/OpenCVImage.java
@@ -81,6 +81,14 @@ class OpenCVImage implements Image {
         return new OpenCVImage(mat);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public Image duplicate() {
+        Mat mat = new Mat();
+        image.copyTo(mat);
+        return new OpenCVImage(mat);
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray toNDArray(NDManager manager, Flag flag) {


Test patch:
diff --git a/examples/src/test/java/ai/djl/testing/TestRequirements.java b/examples/src/test/java/ai/djl/testing/TestRequirements.java
new file mode 120000
index 000000000..c6306acef
--- /dev/null
+++ b/examples/src/test/java/ai/djl/testing/TestRequirements.java
@@ -0,0 +1,1 @@
+../../../../../../../testing/src/main/java/ai/djl/testing/TestRequirements.java
\ No newline at end of file
diff --git a/examples/src/test/java/ai/djl/testing/package-info.java b/examples/src/test/java/ai/djl/testing/package-info.java
new file mode 120000
index 000000000..a42b9ee97
--- /dev/null
+++ b/examples/src/test/java/ai/djl/testing/package-info.java
@@ -0,0 +1,1 @@
+../../../../../../../testing/src/main/java/ai/djl/testing/package-info.java
\ No newline at end of file
diff --git a/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java b/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
index fc1f2a98f..009cb060f 100644
--- a/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
+++ b/extensions/opencv/src/test/java/ai/djl/opencv/OpenCVImageFactoryTest.java
@@ -84,7 +84,8 @@ public class OpenCVImageFactoryTest {
                     Collections.singletonList(new Landmark(0.35, 0.15, 0.5, 0.6, points));
 
             DetectedObjects detectedObjects = new DetectedObjects(list, prob, boundingBoxes);
-            img.drawBoundingBoxes(detectedObjects);
+            Image imgCopy = img.duplicate();
+            imgCopy.drawBoundingBoxes(detectedObjects);
 
             float[][] maskProb = {
                 {1f, 1f, 1f, 1f, 1f, 1f, 1f},
@@ -98,15 +99,15 @@ public class OpenCVImageFactoryTest {
                     Collections.singletonList(new Mask(0.1, 0.5, 0.1, 0.1, maskProb));
 
             DetectedObjects mask = new DetectedObjects(list, prob, masks);
-            img.drawBoundingBoxes(mask);
+            imgCopy.drawBoundingBoxes(mask);
 
             List<Joints.Joint> jointList =
                     Collections.singletonList(new Joints.Joint(0.2, 0.2, 0.8));
             Joints joints = new Joints(jointList);
-            img.drawJoints(joints);
+            imgCopy.drawJoints(joints);
 
             try (OutputStream os = Files.newOutputStream(Paths.get("build/newImage.png"))) {
-                img.save(os, "png");
+                imgCopy.save(os, "png");
             }
 
             Assert.assertThrows(