NVIDIA - Inpainting Demo (nvidia.com)
NVIDIA 上线的一个基于 AI 算法模型的图像修复测试网站. 如图,
网站 pages
文件夹有三个js:ImageMasking.js、ImageSelection.js 和 InpaintingResult.js,其中,ImageMasking.js 内容如下:
import React, { Component } from 'react'
import { Link, Redirect } from 'react-router-dom'
import { isMobile } from 'react-device-detect'
import Modal from 'react-modal'
import { Button } from '@nvidia/kaizen-ui'
import { Subscribe } from 'unstated'
import { AppContainer } from '../../containers'
import { Article, Slider } from '../../components'
import './image-masking.css'
class ImageMaskingComponent extends Component {
constructor(props) {
super(props)
this.state = {
brushSize: 35,
isOpen: false,
showMask: true
}
this.isMouseDown = false
this.canvasWidth = isMobile ? 347 : 512
this.canvasHeight = isMobile ? 347 : 512
}
componentDidMount = () => {
this.linesArray = []
this.startDrawIdx = []
if (this.props.linesArray.length > 0) {
this.linesArray = this.props.linesArray
this.startDrawIdx = this.props.startDrawIdx
this.props.setLinesArray([])
this.redrawCanvas()
}
}
getMousePos = e => {
const rect = this.canvasMask.getBoundingClientRect()
let clientX = e.clientX
let clientY = e.clientY
if (e.touches && e.touches.length > 0) {
clientX = e.touches[0].clientX
clientY = e.touches[0].clientY
}
return {
x: clientX - rect.left,
y: clientY - rect.top
}
}
drawLine = (line, color = '#FFF') => {
this.ctxMask.strokeStyle = color
this.ctxMask.lineWidth = line.size
this.ctxMask.lineCap = 'round'
this.ctxMask.beginPath()
this.ctxMask.moveTo(line.startX, line.startY)
this.ctxMask.lineTo(line.endX, line.endY)
this.ctxMask.stroke()
}
drawStart = e => {
this.isMouseDown = true
this.startDrawIdx.push(this.linesArray.length)
const { x, y } = this.getMousePos(e)
this.x = x
this.y = y
this.draw(e)
}
drawEnd = () => this.isMouseDown = false
draw = e => {
if (!this.isMouseDown) return
const { x, y } = this.getMousePos(e)
const newX = x + 1
const newY = y + 1
const line = {
size: this.state.brushSize,
startX: this.x,
startY: this.y,
endX: newX,
endY: newY
}
this.drawLine(line)
this.linesArray.push(line)
this.x = newX
this.y = newY
}
clearCanvas = () => this.ctxMask.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
redrawCanvas = color => this.linesArray.forEach((line, idx) => this.drawLine(line, color))
handleBrushSizeChange = (event) => this.setState({ brushSize: parseInt(event.target.value, 10) })
uploadNewImage = () => this.props.setSelectedImage('')
applyModel = () => {
// Save the mask array.
this.props.setLinesArray(this.linesArray)
this.props.setStartDrawIdx(this.startDrawIdx)
// Save the mask as show to the user.
const imageMask = this.canvasMask.toDataURL()
this.props.setImageMask(imageMask)
// Process and save the mask to create one for the inference model.
this.clearCanvas()
this.ctxMask.fillStyle = '#FFF'
this.ctxMask.fillRect(0, 0, this.canvasWidth, this.canvasHeight)
this.redrawCanvas('#000')
const processedImageMask = this.canvasMask.toDataURL()
this.props.setProcessedImageMask(processedImageMask)
// Send the request.
this.sendRequest(processedImageMask)
this.openModal()
}
// POST 请求图像修复API
sendRequest = (processedImageMask) => {
var self = this
var data = new FormData()
data.append('original-image-file', this.dataURItoBlob(this.props.selectedImage))
data.append('masked-image-file', this.dataURItoBlob(processedImageMask))
fetch(`${process.env.REACT_APP_SERVICE_ENDPOINT || 'http://52.26.183.137:8080'}/v1/partialconv/inpainting`, {
method: 'POST',
body: data
}).then((response) => response.json())
.then((body) => {
self.props.setResultImage(body.formattedResultImageUrl)
self.props.setRequestId(body.requestId)
self.props.setRequestComplete(true)
})
}
dataURItoBlob = (dataURI) => {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob = new Blob([ab], { type: mimeString });
return blob;
}
clear = () => {
this.clearCanvas()
this.linesArray = []
this.startDrawIdx = []
}
undo = () => {
if (this.startDrawIdx.length > 0) {
this.linesArray.splice(
this.startDrawIdx.pop()
)
this.clearCanvas()
this.redrawCanvas()
}
}
openModal = () => this.setState({ showModal: true })
closeModal = () => this.setState({ showModal: false })
toggleMask = () => this.setState({ showMask: !this.state.showMask})
render() {
const canvasClass = !this.state.showMask ? 'mask-canvas hidden' : 'mask-canvas'
return (
<Article className='image-masking'>
<h2>Step Two</h2>
<span className='subheader'>Use your cursor to mask out any portions of your image,<br />and select Apply Model to view your results.</span>
<div className='canvas'>
<img src={this.props.selectedImage} title='background' alt='background' className='background' />
<canvas
id='#canvas'
width={this.canvasWidth}
height={this.canvasHeight}
ref={canvas => {
if (canvas) {
this.canvasMask = canvas
this.ctxMask = canvas.getContext('2d')
}
}}
onMouseDown={this.drawStart}
onClick={() => false}
onMouseUp={this.drawEnd}
onMouseOut={this.drawEnd}
onMouseMove={this.draw}
onTouchStart={this.drawStart}
onTouchMove={this.draw}
onTouchEnd={this.drawEnd}
onTouchCancel={this.drawEnd}
className={canvasClass}
/>
</div>
<Slider
label='Brush Width:'
value={this.state.brushSize}
onChange={this.handleBrushSizeChange}
step='1'
min='1'
max='100'
/>
<Button.Group className='masking-controls'>
<Button as='div'>
<Link to='selection' onClick={this.uploadNewImage}>Change Image</Link>
</Button>
<Button onClick={this.toggleMask}>
{this.state.showMask ? 'Hide Mask' : 'Show Mask'}
</Button>
<Button onClick={this.clear}>
Clear
</Button>
<Button onClick={this.undo}>
Undo
</Button>
<Button primary onClick={this.applyModel} className='apply-model-button'>
Apply Model
</Button>
</Button.Group>
<Modal
isOpen={this.state.showModal}
className='ui modal'
overlayClassName='ui overlay'
>
<h2 className='title'>Creating Inpainted Image</h2>
<p>Analyzing masks...</p>
<div className='loading-bar' />
</Modal>
</Article>
)
}
}
export const ImageMasking = () =>
<Subscribe to={[AppContainer]}>
{container => (
container.state.requestComplete
? <Redirect to='result' />
: <ImageMaskingComponent {...container.state} {...container} />
)}
</Subscribe>
// WEBPACK FOOTER //
// ./src/pages/ImageMasking/ImageMasking.js